Python的collections模块提供了一个名为namedtuple()的函数,该函数专门设计用于在处理元组时使代码更具Python风格。使用namedtuple(),可以创建不可变的序列类型,允许您使用描述性字段名和点(而不是不明确的整数索引)访问它们的值。
如果您有一些使用Python的经验,那么您就知道编写Pythonic代码是Python开发人员的核心技能。在本教程中,您将使用namedtuple提升该技能。
在本教程中,您将学习如何:
- 使用namedtuple()创建namedtuple类
- 识别并利用namedtuple的特性
- 使用namedtuple实例编写Pythonic代码
- 决定是使用namedtuple还是类似的数据结构
- 将namedtuple子类化以提供新功能
- 元组
- 字典
- 类与面向对象程序设计
- 数据类
- 键入提示
使用namedtuple编写Pythonic代码
Python的namedtuple()是collections中的工厂函数。它允许您创建具有命名字段的元组子类。可以使用点表示法和字段名访问给定命名元组中的值,如obj.attr。
Python的namedtuple是为了提高代码可读性而创建的,它提供了一种使用描述性字段名而不是整数索引来访问值的方法,而整数索引在大多数情况下不提供任何关于值的上下文。这个特性还使代码更干净,更易于维护。
相比之下,对常规元组中的值使用索引可能会很烦人、很难读取并且容易出错。如果元组有很多字段,并且构造的位置离使用元组的位置很远,则尤其如此。
注意:在本教程中,您将发现用于引用Python的namedtuple、工厂函数和实例的不同术语。
为了避免混淆,这里总结了本教程中每个术语的用法:
术语 | 含义 |
---|---|
namedtuple() | 工厂函数 |
namedtuple, classnamedtuple | namedtuple()返回的元组子类 |
namedtuple instance, named tuple | 特定classnamedtuple的实例 |
除了命名元组的这个主要特性之外,您还将发现:
- 不变的数据结构
- 具有一致的哈希值
- 可以用作字典的key
- 可成套存放
- 根据类型和字段名生成有用的docstring
- 提供有用的字符串表示形式,以name=value格式打印元组内容
- 支持索引
- 提供其他方法和属性,如_make(), _asdict(), ._fields 等
- 与常规元组向后兼容
- 具有与常规元组相似的内存消耗
通过对namedtuple及其一般特性的简要介绍,您可以更深入地在代码中创建和使用它们。
使用namedtouple()创建元组式类
您可以使用namedtuple()创建一个不可变的、具有字段名的类元组的数据结构。在有关namedtouple的教程中,您会发现一个流行的例子是创建一个类来表示一个数学点。
根据问题,您可能希望使用不可变的数据结构来表示给定的点。下面演示如何创建正则二维元组point:
Code: Select all
>>> # Create a 2D point as a tuple
>>> point = (2, 4)
>>> point
(2, 4)
>>> # Access coordinate x
>>> point[0]
2
>>> # Access coordinate y
>>> point[1]
4
>>> # Try to update a coordinate value
>>> point[0] = 3
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment
在这里,使用常规方式创建一个不可变的二维元组。这段代码是有效的:你有两个坐标,但不能修改这些坐标中的任何一个。但是这段代码可读吗?你能预先知道索引0和1它代表什么意思吗?为了避免这些歧义,可以这样使用:
Code: Select all
>>> from collections import namedtuple
>>> # Create a namedtuple type, Point
>>> Point = namedtuple("Point", "x y")
>>> issubclass(Point, tuple)
True
>>> # Instantiate the new type
>>> point = Point(2, 4)
>>> point
Point(x=2, y=4)
>>> # Dot notation to access coordinates
>>> point.x
2
>>> point.y
4
>>> # Indexing to access coordinates
>>> point[0]
2
>>> point[1]
4
>>> # Named tuples are immutable
>>> point.x = 100
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: can't set attribute
需要注意的是,虽然元组和命名元组是不可变的,但它们存储的值不一定是不可变的。
创建包含可变值的元组或命名元组是完全合法的:
Code: Select all
>>> from collections import namedtuple
>>> Person = namedtuple("Person", "name children")
>>> john = Person("John Doe", ["Timmy", "Jimmy"])
>>> john
Person(name='John Doe', children=['Timmy', 'Jimmy'])
>>> id(john.children)
139695902374144
>>> john.children.append("Tina")
>>> john
Person(name='John Doe', children=['Timmy', 'Jimmy', 'Tina'])
>>> id(john.children)
139695902374144
>>> hash(john)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'
最后,元组或具有可变值的命名元组是不可散列的,如上面的示例所示。
因为namedtuple类是tuple的子类,所以它们也是不可变的。因此,如果您尝试更改坐标的值,那么您将得到AttributeError。