Python namedtuple 详解:从基础用法到高级特性
本文深入解析Python中namedtuple的使用。介绍其作为collections模块中不可变序列类型的核心优势,包括通过属性名直观访问数据。详细讲解namedtuple()构造函数参数、_make()、_asdict()、_replace()及_fields等常用方法,并结合字典构建、CSV/数据库处理及类继承等实际场景提供代码示例。
namedtuple 概述
namedtuple是Python标准库中用于存储数据的一种特殊数据结构,与常见的list和tuple类似。与list不同,namedtuple中的元素是不可变的,这使得它在需要作为字典键或保持数据完整性时非常有用。
namedtuple的核心概念
namedtuple类定义在collections模块中。使用namedtuple可以让代码通过属性名访问数据,从而提升代码的可读性和可维护性。它创建了一种类似元组的数据类型,既支持索引访问和迭代,又允许通过属性名直接获取字段值。
接下来本文将详细介绍Python namedtuple()的具体用法,并通过实例进行演示。
基本定义与参数
基本定义
调用collections.namedtuple(typename, field_names, *, rename=False, defaults=None, module=None)来创建命名元组。
该函数返回一个名为typename的新元组子类。
这个新子类用于创建类似元组的对象,其字段既可以通过属性查找访问,也可以通过索引和迭代方式访问,字段名由field_names指定。
typename参数说明
typename表示生成的子类的名称,类似于C++、Python或Java中的类名。
field_names参数说明
field_names是一个字符串序列,例如['x', 'y']。
field_names也可以是一个包含空格或逗号分隔的单个字符串,例如'x y'或'x, y'。
其他参数说明
其他参数如rename、defaults和module并不常用,此处不再赘述。
常用方法详解
基本样例
from collections import namedtuple
# 基本例子
Point = namedtuple('Point',['x','y']) # 类名为Point,属性有'x'和'y'
p = Point(11, y=22) # 用位置或关键字参数实例化,因为'x'在'y'前,所以x=11,和函数参数赋值一样的
print(p[0]+p[1]) # 我们也可以使用下标来访问
# 33
x, y = p # 也可以像一个元组那样解析
print(x,y)
# (11, 22)
print(p.x+p.y) # 也可以通过属性名来访问
# 33
print(p) # 通过内置的__repr__函数,显示该对象的信息
# Point(x=11, y=22)
使用somenamedtuple._make(iterable)类方法。
该方法允许从一个序列或可迭代对象中直接对field_names中的属性进行赋值,并返回一个对象实例。
t = [11, 22] # 列表 list
p = Point._make(t) # 从列表中直接赋值,返回对象
print(Point(x=11, y=22))
# Point(x=11, y=22)
使用somenamedtuple._asdict()类方法。
如前所述,namedtuple虽然本质是元组,但其行为更像是一个带有名称的字典。
我们可以直接使用_asdict()方法将其解析为标准的字典dict对象。
p = Point(x=11, y=22) # 新建一个对象
d = p._asdict() # 解析并返回一个字典对象
print(d)
# {'x': 11, 'y': 22}
使用somenamedtuple._replace(**kwargs)类方法。
该方法用于修改某些属性的值,从replace一词即可看出其意图。
需要注意的是,该函数返回的是一个全新的对象,而不会修改原始对象。
p = Point(x=11, y=22) # x=11,y=22
print(p)
# Point(x=11, y=22)
d = p._replace(x=33) # x=33,y=22 新的对象
print(p)
# Point(x=11, y=22)
print(d)
# Point(x=33, y=22)
使用somenamedtuple._fields类方法。
该方法返回该对象的所有属性名,结果以元组形式呈现。
由于返回的是元组,因此支持加法等操作。
print(p._fields) # 查看属性名
# ('x', 'y')
Color = namedtuple('Color', 'red green blue')
Pixel = namedtuple('Pixel', Point._fields + Color._fields) # 新建一个子类,使用多个属性名
q = Pixel(11, 22, 128, 255, 0)
print(q)
使用somenamedtuple._field_defaults类方法。
该方法是Python 3.8新增的功能,由于当前示例环境为3.6,无法直接验证其正确性。
下面给出官方文档中的示例代码。
Account = namedtuple('Account', ['type', 'balance'], defaults=[0])
print(Account._field_defaults)
#{'balance': 0}
print(Account('premium'))
#Account(type='premium', balance=0)
getattr()函数应用
getattr()函数用于动态获取对象的属性值。
print(getattr(p, 'x'))
# 11
通过字典创建namedtuple对象
演示如何从字典构建namedtuple对象。
d = {'x': 11, 'y': 22} # 字典
p = Point(**d) # 双星号是重点
print(p)
# Point(x=11, y=22)
实际应用场景
处理CSV或SQLite3数据
同样可以将从CSV文件或数据库中读取的数据存储到namedtuple中。
在此场景中,每次处理的内容通常是一行数据。
EmployeeRecord = namedtuple('EmployeeRecord', 'name, age, title, department, paygrade')
import csv
for emp in map(EmployeeRecord._make, csv.reader(open("employees.csv", "r"))):
# 这里每行返回一个对象 注意!
print(emp.name, emp.title)
import sqlite3
conn = sqlite3.connect('/companydata') # 连接数据库
cursor = conn.cursor()
cursor.execute('SELECT name, age, title, department, paygrade FROM employees')
for emp in map(EmployeeRecord._make, cursor.fetchall()):
# 每行返回一个对象 注意!
print(emp.name, emp.title)
继承与扩展
类的继承应用
接下来,我们将使用DeepMind开源项目graph_nets中的一段代码来介绍namedtuple的继承用法。
NODES = "nodes"
EDGES = "edges"
RECEIVERS = "receivers"
SENDERS = "senders"
GLOBALS = "globals"
N_NODE = "n_node"
N_EDGE = "n_edge"
GRAPH_DATA_FIELDS = (NODES, EDGES, RECEIVERS, SENDERS, GLOBALS)
GRAPH_NUMBER_FIELDS = (N_NODE, N_EDGE)
class GraphsTuple(
# 定义元组子类名 以及字典形式的键名(属性名)
collections.namedtuple("GraphsTuple",
GRAPH_DATA_FIELDS + GRAPH_NUMBER_FIELDS)):
# 这个函数用来判断依赖是否满足,和我们的namedtuple关系不大
def _validate_none_fields(self):
"""Asserts that the set of `None` fields in the instance is valid."""
if self.n_node is None:
raise ValueError("Field `n_node` cannot be None")
if self.n_edge is None:
raise ValueError("Field `n_edge` cannot be None")
if self.receivers is None and self.senders is not None:
raise ValueError(
"Field `senders` must be None as field `receivers` is None")
if self.senders is None and self.receivers is not None:
raise ValueError(
"Field `receivers` must be None as field `senders` is None")
if self.receivers is None and self.edges is not None:
raise ValueError(
"Field `edges` must be None as field `receivers` and `senders` are "
"None")
# 用来初始化一些参数 不是重点
def __init__(self, *args, **kwargs):
del args, kwargs
# The fields of a `namedtuple` are filled in the `__new__` method.
# `__init__` does not accept parameters.
super(GraphsTuple, self).__init__()
self._validate_none_fields()
# 这就用到了_replace()函数,注意只要修改了属性值
# 那么就返回一个新的对象
def replace(self, **kwargs):
output = self._replace(**kwargs) # 返回一个新的实例
output._validate_none_fields() # pylint: disable=protected-access 验证返回的新实例是否满足要求
return output
# 这是为了针对tensorflow1版本的函数
# 返回一个拥有相同属性的对象,但是它的属性值是输入的大小和类型
def map(self, field_fn, fields=GRAPH_FEATURE_FIELDS): # 对每个键应用函数
"""Applies `field_fn` to the fields `fields` of the instance.
`field_fn` is applied exactly once per field in `fields`. The result must
satisfy the `GraphsTuple` requirement w.r.t. `None` fields, i.e. the
`SENDERS` cannot be `None` if the `EDGES` or `RECEIVERS` are not `None`,
etc.
Args:
field_fn: A callable that take a single argument.
fields: (iterable of `str`). An iterable of the fields to apply
`field_fn` to.
Returns:
A copy of the instance, with the fields in `fields` replaced by the result
of applying `field_fn` to them.
"""
return self.replace(**{k: field_fn(getattr(self, k)) for k in fields}) # getattr(self, k) 获取的是键值对中的值, k表示键
到此,关于Python中namedtuple使用的详解文章介绍完毕。更多相关python namedtuple的使用内容请搜索本站以前的文章或继续浏览下面的相关文章,希望大家以后多多支持本站!
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









