namedtuple
是 Python 标准库 collections
模块提供的一个工厂函数,用于创建带有命名字段的元组子类。它结合了元组和字典的优点,既有元组的不可变性和性能,又能像字典一样通过名称访问元素。
_asdict()
, _replace()
等普通元组需要通过索引访问元素:
point = (1, 2)
x = point[0] # 可读性差,不知道0代表什么
使用 namedtuple:
from collections import namedtuple
Point = namedtuple('Point', ['x', 'y'])
p = Point(1, 2)
x = p.x # 可读性更好
普通类定义:
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
使用 namedtuple 只需一行:
Point = namedtuple('Point', 'x y')
比字典更节省内存,访问速度更快:
# 字典方式
person_dict = {'name': 'Alice', 'age': 25, 'gender': 'F'}
# namedtuple方式
Person = namedtuple('Person', 'name age gender')
person_nt = Person('Alice', 25, 'F')
from collections import namedtuple
# 方法1:字段名列表
Person = namedtuple('Person', ['name', 'age', 'gender'])
# 方法2:字段名字符串(空格分隔)
Person = namedtuple('Person', 'name age gender')
# 方法3:字段名字符串(逗号分隔)
Person = namedtuple('Person', 'name, age, gender')
# 位置参数
p1 = Person('Alice', 25, 'F')
# 关键字参数
p2 = Person(name='Bob', age=30, gender='M')
# 混合使用
p3 = Person('Charlie', gender='M', age=35)
print(p1.name) # 'Alice'
print(p1[0]) # 'Alice' (仍然支持索引访问)
print(p1.age) # 25
print(p1.gender) # 'F'
try:
p1.age = 26 # 尝试修改
except AttributeError as e:
print(e) # "can't set attribute"
od = p1._asdict()
print(od) # OrderedDict([('name', 'Alice'), ('age', 25), ('gender', 'F')])
p1_new = p1._replace(age=26)
print(p1) # Person(name='Alice', age=25, gender='F')
print(p1_new) # Person(name='Alice', age=26, gender='F')
print(Person._fields) # ('name', 'age', 'gender')
values = ['Dave', 40, 'M']
p4 = Person._make(values)
print(p4) # Person(name='Dave', age=40, gender='M')
Person.__doc__ = 'Representation of a person'
# 或者在创建时添加
Person = namedtuple('Person', 'name age gender',
defaults=[None, None, None],
module='__main__')
Person.__doc__ = 'Representation of a person'
Person = namedtuple('Person', 'name age gender', defaults=[None, None, 'Unknown'])
p = Person('Alice')
print(p) # Person(name='Alice', age=None, gender='Unknown')
from typing import NamedTuple
class Employee(NamedTuple):
name: str
id: int
department: str = 'Unassigned'
emp = Employee('Alice', 1234)
print(emp) # Employee(name='Alice', id=1234, department='Unassigned')
# 字典转namedtuple
data = {'name': 'Alice', 'age': 25, 'gender': 'F'}
p = Person(**data)
# namedtuple转字典
dict_data = p._asdict()
import sqlite3
conn = sqlite3.connect('example.db')
cursor = conn.cursor()
cursor.execute('SELECT name, age, gender FROM users')
# 将查询结果转为namedtuple
User = namedtuple('User', 'name age gender')
users = [User._make(row) for row in cursor.fetchall()]
for user in users:
print(f'{user.name} is {user.age} years old')
import csv
with open('data.csv') as f:
reader = csv.reader(f)
header = next(reader)
Data = namedtuple('Data', header)
for row in reader:
data = Data._make(row)
print(data.id, data.value)
def get_user_info(user_id):
# 模拟数据库查询
name = "Alice" if user_id == 1 else "Bob"
age = 25 if user_id == 1 else 30
return namedtuple('UserInfo', 'name age')(name, age)
info = get_user_info(1)
print(info.name, info.age)
特性 | namedtuple | 普通元组 | 字典 | 类实例 |
---|---|---|---|---|
不可变性 | ✔ | ✔ | ✘ | ✘ |
命名访问 | ✔ | ✘ | ✔ | ✔ |
内存效率 | 高 | 高 | 较低 | 较高 |
访问速度 | 最快 | 快 | 较快 | 较快 |
支持默认值 | ✔ (Python 3.7+) | ✘ | ✔ | ✔ |
方法支持 | 有限 | 无 | 丰富 | 可自定义 |
字段命名规则:
# 无效字段名示例
try:
Point = namedtuple('Point', ['x', 'y', 'def'])
except ValueError as e:
print(e) # Type names and field names cannot be a keyword: 'def'
性能考虑:
继承限制:
Python版本差异:
defaults
参数typing.NamedTuple
_field_defaults
namedtuple
是Python中一个非常实用的数据结构,特别适合以下场景:
通过本文,你应该已经掌握了:
在合适的场景下使用namedtuple,可以使你的代码更加简洁、高效和易读。