python——collections模块(namedtuple)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/wzyaiwl/article/details/89233722

namedtuple

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))   #<class '__main__.point'>
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()
  • 命名元组还可以通过_replace()方法改变内部的值,但不能改变原来的值,所以必须把改变后的point传给另一个变量才行。
  • 命令元组还可以通过_asdict()方法将其转为OrderedDict对象,这个对象在后面会介绍到。
  • 命令元组的属性名是不能重复或使用关键字,否则会报错。要想不报错,且自动更改别的名字,需要在创建tuple对象时加入参数rename=True。

下面自定义元组对象,存放圆的圆心和半径。

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 <module>
    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

猜你喜欢

转载自blog.csdn.net/wzyaiwl/article/details/89233722
今日推荐