python中的元组相信使用python的人都很熟悉,元组的访问一般都是通过索引来获取。但其有一个“兄弟”元组,叫做“命名元组”,其功能更加强大,即你不仅可以通过索引来获取,也可以通过名字来获取。
namedtuple是一个函数,可以用来自定义一个tuple对象,并且自己规定元组中元素的个数。这样一来,我们用namedtuple
可以很方便地定义一种数据类型,它具备tuple的不变性,又可以根据属性来引用,使用十分方便。
下面的例子我们自定义一个存放坐标的元组,元组内的两个元素分别命名为x、y。
from collections import namedtuple
point = namedtuple('point',['x','y'])
a = point(4,5)
print(a) #point(x=4, y=5)
print(type(a)) #
print(isinstance(a,point)) #True
print(a.x) #4
print(a.y) #5
print(tuple(a)) #(4, 5)
print(a._asdict()) #OrderedDict([('x', 4), ('y', 5)])
print(a._replace(x= 66)) #point(x=66, y=5)
首先用namedtuple创建一个tuple对象。创建时传入的两个参数,‘point’是这个tuple对象的名字,第二个参数是一个列表,储存着各个元素对应的名字。传入4和5后,我们就可以通过属性名x和y来访问它们。第二个参数可以传入一个列表,也可以传入一个字符串,字符串各个属性名以空格隔开就好了。这是因为其源码内部会自动将其处理成一个列表。部分源码如下所示:
if isinstance(field_names, str):
field_names = field_names.replace(',', ' ').split()
下面自定义元组对象,存放圆的圆心和半径。
from collections import namedtuple
cicrle = namedtuple('cicrle',['x','x','class'])
a = cicrle(4,5,20)
print(a)
由于属性名filename出现重复和关键字,所以会报如下错误。
Traceback (most recent call last):
File "D:/Spider_base/test.py", line 3, in
cicrle = namedtuple('cicrle',['x','x','class'])
File "D:\Spider_base\venv\lib\collections\__init__.py", line 404, in namedtuple
'keyword: %r' % name)
ValueError: Type names and field names cannot be a keyword: 'class'
如果加入参数rename,结果如下:
from collections import namedtuple
cicrle = namedtuple('cicrle',['x','x','class'],rename=True )
a = cicrle(4,5,20)
print(a)
cicrle(x=4, _1=5, _2=20)
为什么自动改的名字是_1、_2?这个rename效果原理如下:
if rename:
seen = set()
for index, name in enumerate(field_names):
if (not name.isidentifier()
or _iskeyword(name)
or name.startswith('_')
or name in seen):
field_names[index] = '_%d' % index
seen.add(name)
上述源码中,先判断rename参数是否为True,若为True,执行下面。首先定义一个集合seen,然后将field_names枚举循环判断,isidentifier()方法是用来判断变量名是否合法。
再判断name是否是关键字,_iskeyword方法通过下面导包。再判断name是否以_开头,最后判断name是否已经在seen集合内,只要满足上述任何一个条件,就判定为name属性不符合要求,从而以‘_index’来重命名。
from keyword import iskeyword as _iskeyword