📚 collections.namedtuple 学习指南
命名元组(namedtuple
)是 Python collections
模块中一种增强型元组,支持通过字段名访问元素,同时保持元组的内存效率和不可变性。
一、基础用法
1. 定义命名元组
from collections import namedtuple
# 定义 Point 类型(字段名用空格或列表分隔)
Point = namedtuple('Point', ['x', 'y'])
# 或简写为
Point = namedtuple('Point', 'x y')
# 实例化对象
p = Point(10, y=20) # 类似常规元组或类构造
print(p) # 输出: Point(x=10, y=20)
2. 访问元素
print(p.x) # 10(通过字段名)
print(p[0]) # 10(通过索引,保留元组特性)
二、核心特性
1. 不可变性
命名元组继承自普通元组,元素不可修改:
# 以下操作会报错
p.x = 100 # AttributeError: can't set attribute
2. 轻量级类替代
相比传统类,命名元组更简洁:
# 等价于以下类定义
class PointClass:
def __init__(self, x, y):
self.x = x
self.y = y
三、方法与属性
1. 常用方法
方法 | 功能 | 示例 |
---|---|---|
_asdict() |
转为 OrderedDict |
p._asdict() → {'x':10, 'y':20} |
_replace(**kwargs) |
创建新实例并替换字段值 | p._replace(x=100) → Point(x=100, y=20) |
_make(iterable) |
通过可迭代对象创建实例 | Point._make([30, 40]) → Point(x=30, y=40) |
2. 元数据属性
print(p._fields) # 输出字段名元组: ('x', 'y')
# 可扩展新类型(通过继承)
Point3D = namedtuple('Point3D', Point._fields + ('z',))
四、进阶应用
1. 字典互转
# 转字典(Python 3.7+ 返回普通字典)
d = p._asdict() # {'x': 10, 'y': 20}
# 从字典创建
data = {'x': 30, 'y': 40}
p_new = Point(**data) # Point(x=30, y=40)
2. 默认值与可选参数
通过定义子类添加默认值:
class PointDefault(Point):
__slots__ = ()
def __new__(cls, x=0, y=0):
return super().__new__(cls, x, y)
p_default = PointDefault() # Point(x=0, y=0)
3. 添加方法
class PointWithMethods(Point):
def distance(self, other):
return ((self.x - other.x)**2 + (self.y - other.y)**2)**0.5
p1 = PointWithMethods(1, 2)
p2 = PointWithMethods(4, 6)
print(p1.distance(p2)) # 输出 5.0
五、实际应用场景
1. 数据库查询结果
import sqlite3
conn = sqlite3.connect('example.db')
cursor = conn.cursor()
cursor.execute('SELECT id, name, age FROM users')
# 将每行转为命名元组
User = namedtuple('User', 'id name age', module=__name__)
users = [User(*row) for row in cursor.fetchall()]
print(users[0].name) # 通过字段名访问数据
2. CSV 文件解析
import csv
with open('data.csv') as f:
reader = csv.reader(f)
header = next(reader)
Row = namedtuple('Row', header)
for r in reader:
row = Row(*r)
print(row.date, row.value) # 按字段名访问列
3. 替代简单类
# 表示 RGB 颜色
Color = namedtuple('Color', 'red green blue')
white = Color(255, 255, 255)
# 函数返回多个命名值
def get_dimensions():
return namedtuple('Size', 'width height')(1920, 1080)
screen = get_dimensions()
print(f"分辨率: {screen.width}x{screen.height}")
六、命名元组 vs 其他数据结构
特性 | 命名元组 | 字典 | 普通类 |
---|---|---|---|
内存占用 | 小 | 较大 | 较大 |
访问速度 | 快速(通过索引和字段名) | 略慢(哈希查找) | 略慢(属性访问) |
可变性 | 不可变 | 可变 | 可变 |
语法简洁性 | 高 | 高 | 低(需定义类) |
代码可读性 | 高(明确字段名) | 一般 | 高 |
七、注意事项
1. 字段名规范
- 字段名不能是 Python 关键字(如
class
,def
)。 - 字段名不可重复,否则报错:
# 错误示例 Invalid = namedtuple('Invalid', 'x x') # ValueError: 重复字段名
2. 不可变性的权衡
- 优点:线程安全、哈希可用性(可作为字典键)。
- 缺点:需要创建新实例以实现“修改”。
八、总结
命名元组是以下场景的理想选择:
- 需要轻量级不可变数据结构。
- 希望通过字段名提高代码可读性。
- 需将数据作为字典键使用(普通字典键需用元组)。
进一步学习:
- Python 官方文档 - namedtuple
- 探索
typing.NamedTuple
(Python 3.6+)以支持类型注解!