namedtuple工厂函数,创造一个像实例对象的元祖(感觉到了Python的奇妙与可爱之处)。
发现了namedtuple将大大的方便对象实例化的过程,底层我觉的应该应用了描述符的相关指令__set__,__get__,__delete__等等,深的不讲了,我给自己记号一下如何把这个函数用好。
基本概念
namedtuple
是一个 工厂函数,定义在python
标准库的collections
模块中,使用此函数可以创建一个可读性更强的元组namedtuple
函数所创建(返回)的是一个 元组的子类(python中基本数据类型都是类,且可以在buildins
模块中找到)namedtuple
函数所创建元组,中文名称为 具名元组- 在使用普通元组的时候,我们只能通过
index
来访问元组中的某个数据 - 使用具名元组,我们既可以使用
index
来访问,也可以使用具名元组中每个字段的名称来访问 - 值得注意的是,具名元组和普通元组所需要的内存空间相同,所以 不必使用性能来权衡是否使用具名元组
if sys.version_info >= (3, 7): def namedtuple(typename: str, field_names: Union[str, Iterable[str]], *, rename: bool = ..., module: Optional[str] = ..., defaults: Optional[Iterable[Any]] = ...) -> Type[tuple]: ... elif sys.version_info >= (3, 6): def namedtuple(typename: str, field_names: Union[str, Iterable[str]], *, verbose: bool = ..., rename: bool = ..., module: Optional[str] = ...) -> Type[tuple]: ... else: def namedtuple(typename: str, field_names: Union[str, Iterable[str]], verbose: bool = ..., rename: bool = ...) -> Type[tuple]: ...
进去源码里面可以看到,应该当Python的版本不同时,里面的默认参数也会不同,我是3.7的,我看的数版本肯定不是3.7的,所以介绍的里面不全。
第一个参数:typename是调用namedtuple函数时作为新创建的类名称。
第二个参数:field_names可以传入str或者可迭代的对象的str['color','age']类似这种,或者字符串'color age'属性之间必须空格,内部应该执行了split命令,还有就是里面的str不能是Python里面的关键字,比如def,class。
后面的参数书上没介绍,网上找来部分资料。
rename
- 注意的参数中使用了
*
,其后的所有参数必须指定关键字 - 参数为布尔值
- 默认为
False
。当我们指定为True
时,如果定义field_names
参数时,出现非法参数时,会将其替换为位置名称。如['abc', 'def', 'ghi', 'abc']
会被替换为['abc', '_1', 'ghi', '_3']
defaults
- 参数为
None
或者可迭代对象 - 当此参数为
None
时,创建具名元组的实例时,必须要根据field_names
传递指定数量的参数 - 当设置
defaults
时,我们就为具名元组的元素赋予了默认值,被赋予默认值的元素在实例化的时候可以不传入 - 当
defaults
传入的序列长度和field_names
不一致时,函数默认会右侧优先 - 如果
field_names
是['x', 'y', 'z']
,defaults
是(1, 2)
,那么x
是实例化必填参数,y
默认为1
,z
默认为2
from collections import namedtuple Car = namedtuple('Car', 'color brand def', rename=True, defaults=('red', 'honda')) car = Car('temp') # 初始化实例,由于前面已经有了两个默认值,就填写了少的一个 print(car) # 输出实现显示格式,Car(color='temp', brand='red', _2='honda') # 很好玩的默认赋值方式,默认的赋值是从后面往前面自动匹配,因为我最后的是非法字符def # rename选项打开以后自动转换成字符_2,然后进行赋值 print(car.color) # 通过.取出属性 print(car[1]) # 通过索引取出属性 print(''.join(car)) # 有着元祖的特性进行内容拼接。 car.color = 'blue' # 有着元祖的特性,内部元素不容修改
Traceback (most recent call last): File "/Users/shijianzhong/Desktop/bit_coin/test_file/test_namedtuple.py", line 10, in <module> car.color = 'blue' AttributeError: can't set attribute Car(color='temp', brand='red', _2='honda') temp red tempredhonda
通过代码显示可以看出,实例出来的对象既有元祖的全部特性,还像一个只读的自定义对象。类似MappingProxyType(实例)
namefile还提供了一些游泳的辅助方法。
第一个_fields,用继续另外一个基类元祖的字段。
print(Car._fields)
('color', 'brand', '_2')
直接输出Car的字段,将三个属性输出,所以,如果想继承的话,可以这么写
Car2 = namedtuple('Car2', Car._fields+('other',))
print(car._asdict())
OrderedDict([('color', 'temp'), ('brand', 'red'), ('_2', 'honda')])
生成了一个有序的字典,这样的话,就可以按照字典的方式,随意操作了。
第三个是_replace,用来替换里面的参数,返回一个新实例
n_car = car._replace(brand='blue') print(n_car)
Car(color='1', brand='blue', _2='temp')
这个刚开犯傻了一下,以为是列表没有给予赋值,car自身会发生变换,还是脑子秀逗了,对于元祖的任何操作,跟字符串都一样,因为对象本身是不可变的,所以当有变化发生时,需要变量名来接受修改后的参数。
最后一个_make类方法,用来从序列或迭代对象中创建nametuple的新实例。
car2 = Car._make(['purple','audi','tt']) print(car2)
Car(color='1', brand='blue', _2='temp') Car(color='purple', brand='audi', _2='tt')
最后的参数链接,作者写的比我详细,大家可以参考学习下。