目录

一、绪论

二、namedtuple 函数

2.1 说明


一、绪论


collections 作为 Python 的内建集合模块,实现了许多十分高效的特殊容器数据类型,即除了 Python 通用内置容器: dict、list、set 和 tuple 等的替代方案。在 IDLE 输入 help(collections) 可查看帮助文档,其中常见的类/函数如下:

名称

功能

namedtuple

用于创建具有命名字段的 tuple 子类的 factory 函数 (具名元组)

deque

类似 list 的容器,两端都能实现快速 append 和 pop (双端队列)

ChainMap

类似 dict 的类,用于创建多个映射的单视图

Counter

用于计算 hashable 对象的 dict 子类 (可哈希对象计数)

OrderedDict

记住元素添加顺序的 dict 子类 (有序字典)

defaultdict

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(typenamefield_names*verbose=Falserename=Falsemodule=None)

namedtuple,顾名思义是已具命名的元组 (简称具名元组),它返回一个 tuple 子类。

其中,namedtuple 名称为参数 typename,各字段名称为参数 field_names

其中,field_names 既可以是一个类似 ['x', 'y'] 的字符串序列 (string-seq),也可以是用空格或逗号分隔开的纯字符串 string,如 'x y' 或 'x, y'。任何 Python 的有效标识符都可作为字段名。所谓有效标识符由字母,数字,下划线组成,但首字母不能是数字或下划线,且不能与 Python 关键词重复,如 classforreturn 等。

具名元组 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 文档

Python namedtuple