Python数据结构:利用命名元组解耦序列访问
本文介绍Python中如何使用命名元组(namedtuple)将名称映射到序列元素,从而减少对位置索引的依赖。通过对比普通元组,展示namedtuple在提高代码可读性方面的优势,并详解其不可变性、_replace方法的使用及处理可选字段的技巧。
本文介绍一种在Python中将名称映射到序列元素的方法,供读者参考学习。
核心问题在于:如何通过名称直接访问元素,从而降低代码对序列中具体位置索引的依赖。
解决方案是采用命名元组collections.namedtuple()。这是一个工厂函数,用于生成标准元组类型的子类。用户需提供类型名称及字段名称,该函数将返回一个可实例化的类,允许通过预定义的字段名传入值并进行访问。
命名元组的核心价值在于实现代码逻辑与底层元素位置之间的解耦。
>>> from collections import namedtuple
>>> Sub=namedtuple('Subscriber',['addr','joined'])
>>> subscriber=Sub('lucy@example.com','2016-8-7')
>>> subscriber
Subscriber(addr='lucy@example.com', joined='2016-8-7')
>>> subscriber.addr
'lucy@example.com'
>>> subscriber.joined
'2016-8-7'
命名元组namedtuple的实例与普通元组完全兼容,支持所有标准元组操作,包括索引访问和序列解包(unpacking)。
>>> len(subscriber) 2 >>> addr,joined=subscriber >>> addr 'lucy@example.com' >>> joined '2016-8-7' >>>
以下是使用普通元组的代码示例:
def compute_cost(records):
total = 0.0
for rec in records:
total += rec[1] * rec[2]
return total
仅通过位置索引引用元素会导致代码可读性较差,且紧密耦合于数据结构的具体定义,一旦结构变化,所有引用处均需修改。
以下是使用命名元组重构后的代码版本:
# example.py
from collections import namedtuple
Stock = namedtuple('Stock', ['name', 'shares', 'price'])
def compute_cost(records):
total = 0.0
for rec in records:
s = Stock(*rec)
total += s.shares * s.price
return total
# Some Data
records = [
('GOOG', 100, 490.1),
('ACME', 100, 123.45),
('IBM', 50, 91.15)
]
print(compute_cost(records))
程序运行输出结果如下:
65912.5
补充说明:
在构建涉及字典的大型数据结构时,使用namedtuple通常比直接使用字典更高效。但需注意,namedtuple实例是不可变的。例如尝试直接修改属性会引发错误:
>>> s=Stock('ACMS',100,123.45)
>>> s
Stock(name='ACMS', shares=100, price=123.45)
>>> s.shares=75
Traceback (most recent call last):
File "<pyshell#2>", line 1, in <module>
s.shares=75
AttributeError: can't set attribute
>>>
若需修改属性值,应使用命名元组实例的_replace()方法。该方法不会原地修改,而是创建一个新的命名元组实例,并将指定字段的值替换为新值。
>>> s=s._replace(shares=75) >>> s Stock(name='ACMS', shares=75, price=123.45) >>>
_replace()方法还有一个巧妙用法:它可以作为填充具有可选或缺失字段的命名元组的便捷手段。
具体操作步骤如下:
首先,创建一个包含默认值的“原型”元组实例;
然后,利用_replace()方法创建新实例,通过传入字典参数将特定值替换到对应字段中;
from collections import namedtuple
Stock = namedtuple('Stock', ['name', 'shares', 'price','date','time'])
#创建一个包含默认值的“原型”元组
stock_prototype=Stock('',0,0.0,None,None)
#创建一个函数实现将字典转化为Stock类型
def dict_to_stock(s):
return stock_prototype._replace(**s)
a={'name':'ACMS','shares':100,'price':123.45}
print(dict_to_stock(a))
b={'name':'ACMS','shares':100,'price':123.45,'date':'2016-08-08'}
print(dict_to_stock(b))
c={'name':'ACMS','price':123.45}
print(dict_to_stock(c))
运行上述代码的输出结果如下:
Stock(name='ACMS', shares=100, price=123.45, date=None, time=None) Stock(name='ACMS', shares=100, price=123.45, date='2016-08-08', time=None) Stock(name='ACMS', shares=0, price=123.45, date=None, time=None)
注意:如果设计目标是定义高性能数据结构,且预期未来需要频繁修改各个实例的属性,那么不建议使用namedtuple,应考虑使用字典或其他可变数据结构。
(相关代码示例摘自《Python Cookbook》)
感兴趣读者可进一步查阅本站相关专题:《Python数据结构与算法教程》、《Python函数使用技巧总结》、《Python字符串操作技巧汇总》、《Python入门与进阶经典教程》及《Python文件与目录操作技巧汇总》。
希望本文关于Python程序设计的阐述能对大家有所帮助。
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













