目录
一、绪论
二、namedtuple 函数
2.1 说明
一、绪论
collections 作为 Python 的内建集合模块,实现了许多十分高效的特殊容器数据类型,即除了 Python 通用内置容器: dict、list、set 和 tuple 等的替代方案。在 IDLE 输入 help(collections) 可查看帮助文档,其中常见的类/函数如下:
名称 | 功能 |
namedtuple | 用于创建具有命名字段的 tuple 子类的 factory 函数 (具名元组) |
类似 list 的容器,两端都能实现快速 append 和 pop (双端队列) | |
ChainMap | 类似 dict 的类,用于创建多个映射的单视图 |
用于计算 hashable 对象的 dict 子类 (可哈希对象计数) | |
OrderedDict | 记住元素添加顺序的 dict 子类 (有序字典) |
dict 子类调用 factory 函数来提供缺失值 | |
UserDict | 包装 dict 对象以便于 dict 的子类化 |
UserList | 包装 list 对象以便于 list 的子类化 |
UserString | 包装 string 对象以便于 string 的子类化 |
而本文详述的对象为具名/命名元组 —— namedtuple 。
二、namedtuple 函数
Python 内建普通元组 tuple 存在一个局限,即不能为 tuple 中的元素命名,故 tuple 所要表达的意义并不明显。
因此,引入一工厂函数 (factory function) collections.namedtuple,以构造一个带字段名的 tuple。具名元组 namedtuple 的实例和普通元组 tuple 消耗的内存一样多 (因为字段名都被保存在对应的类中) 但却更具可读性 (namedtuple 使 tuple 变成自文档,根据字段名很容易理解用途),令代码更易维护;同时,namedtuple 不用命名空间字典(namespace dictionary) __dict__ 来存放/维护实例属性,故比普通 dict 更加轻量和快速。但注意,具名元组 namedtuple 继承自 tuple ,其中的属性均不可变。
2.1 说明
collections.namedtuple(typename, field_names, *, verbose=False, rename=False, module=None)
namedtuple,顾名思义是已具命名的元组 (简称具名元组),它返回一个 tuple 子类。
其中,namedtuple 名称为参数 typename,各字段名称为参数 field_names。
其中,field_names 既可以是一个类似 ['x', 'y'] 的字符串序列 (string-seq),也可以是用空格或逗号分隔开的纯字符串 string,如 'x y' 或 'x, y'。任何 Python 的有效标识符都可作为字段名。所谓有效标识符由字母,数字,下划线组成,但首字母不能是数字或下划线,且不能与 Python 关键词重复,如 class, for, return 等。
具名元组 namedtuple 向后兼容普通 tuple,从而既可通过 field_names 获取元素值/字段值,也能通过索引和迭代获取元素值/字段值。
>>> from collections import namedtuple
# Point = namedtuple("Point", 'x, y') # 等价的初始化方式
# Point = namedtuple("Point", 'x y') # 等价的初始化方式
>>> Point = namedtuple("Point", ['x', 'y']) # 初始化一个具名元组 Point
>>> Point
<class '__main__.Point'>
# -------------------------------------------------------------------------
>>> p1 = Point(2, 3) # 实例化一个具名元组 Point 对象 p1
>>> p1 # 可读 (readable __repr__ with a name=value style)
Point(x=2, y=3)
# -------------------------------------------------------------------------
>>> p1.x # 通过字段名获取元素值/字段值 (fields also accessible by name)
2
>>> p1[0] # 通过索引获取元素值/字段值 (indexable like the plain tuple (2, 3))
2
>>> for i in p1: # 通过迭代获取元素值/字段值
print(i)
2
3
# -------------------------------------------------------------------------
>>> a, b = p1 # 能够像普通 tuple 一样解绑 (unpack like a regular tuple)
>>> a, b
(2, 3)
除继承普通 tuple,具名元组 nametuple 还额外支持三个方法和两个属性。为防止名称冲突,方法和属性以下划线开始:
- 类属性 _fields:包含本类所有字段名的元组 tuple
- 类方法 _make(iterable):接受一个序列 sequence 或可迭代对象 iterable 来生成本类的实例
- 实例方法 _replace(**kwargs):基于本实例修改、替换元素来生成本类的实例
- 实例方法 _asdict():将具名元组以 collections.OrdereDict 的形式返回,用于友好地展示元组信息
- 实例方法 _source:略...
>>> from collections import namedtuple
>>> Point2 = namedtuple("Point2", 'x, y') # 初始化一个具名元组对象 Point2
>>> p2 = Point2(1, 4)
>>> p2
Point2(x=1, y=4)
# -------------------------------------------------------------------------
>>> p2._fields # 获取所有字段名构成的 tuple
('x', 'y')
# -------------------------------------------------------------------------
>>> p21 = p2._make([5, 6]) # 使用 list 实例化一个新 Point2 对象
>>> p21
Point2(x=5, y=6)
>>> p2
Point2(x=1, y=4) # 原 namedtuple 不变
# -------------------------------------------------------------------------
>>> p22 = p2._replace(y=4.5) # 使用关键字参数修改并实例化一个新 Point2 对象
>>> p22
Point2(x=1, y=4.5)
>>> p2
Point2(x=1, y=4) # 原 namedtuple 不变
# -------------------------------------------------------------------------
>>> p2._asdict() # 将 namedtuple 对象转换为 OrderedDict 对象
OrderedDict([('x', 1), ('y', 4)])
>>> p2
Point2(x=1, y=4) # 原 namedtuple 不变
注意,上述方法 均非“原地操作” (in-place) 方法,因为 tuple / namedtuple 是不可变对象!只能创建新的。
若参数 rename=True,无效字段名 field_names 会自动转换成位置名。例如 ['abc', 'def', 'ghi', 'abc'] 转换成 ['abc', '_1', 'ghi', '_3'],转换并消除了关键词 def 和重复域名 abc。否则,在创建伊始就会抛出 ValueError。
>>> Point3 = namedtuple("Point3", ['abc', 'def', 'ghi', 'abc'], rename=True)
>>> p3 = Point3(3, 5, 7, 9)
>>> p3._fields
('abc', '_1', 'ghi', '_3')
>>> p3
Point3(abc=3, _1=5, ghi=7, _3=9)
此外,将 dict 转换为 namedtuple 可使用双星操作符 ** (double-star-operator) 进行解包实现:
>>> dict4 = {'x':14, 'y':16}
>>> Point4 = namedtuple("Point4", 'x y')
>>> p4 = Point4(**dict4)
>>> p4
Point4(x=14, y=16)
至于 verbose 参数和 module 参数并不常用,不作赘述。
参考文献
《Python Immediate》
8.3. collections — 容器数据类型 — Python 3.6.15 文档