目录
- 问题
- 解决方案
- 讨论
问题
对于访问列表或元组中的元素,我们通常使用索引或者下标的方法。但是这明显会降低代码的可阅读性。如果我们想通过命名来提高代码的可阅读性,减少结构中对位置的依赖,怎么做?
解决方案
python 提供 collection.namedtuple()
方法(本文中称:命名元组),其根据提供的类型名称以及相应的字段,返回一个可实例化的类,包含定义好的字段传入值等:
from collections import namedtuple
Subscriber = namedtuple('Subscriber', ['addr', 'joined'])
sub = Subscriber('x.hongd@hamail.com', '2012-12-31')
print("sub = ", sub)
print("sub.addr = ", sub.addr)
print("sub.joined = ", sub.joined)
同其他的元组一样,namedtuple()
函数支持所有普通元组的操作,例如分解:
addr, joined = sub
print("addr = ", addr)
print("joined = ", joined)
重要的是,命名元组 的主要作用在于将代码同它控制的元素位置间解耦。即,假如我们通过元素的位置来访问数据,当表单中新增一列数据时,会导致代码崩溃不可用,但是如果事先将返回的元组转型为 命名元组,即 namedtuple()
,只需微调即可:
# 同控制的元素位置间未解耦
def compute_cost(records):
total = 0.0
for rec in records:
total += rec[1] * rec[2]
return total
# 解耦
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
Stock(*rec)
这行代码使用 * 操作符来解包 rec 元组,将其中的每个元素作为参数传递给 Stock 构造函数,创建一个新的 Stock 对象 s。如此,s 就有了 name、shares 和 price 属性,可以直接通过属性访问。
讨论
namedtuple()
对比字典,其占用更小的空间来存储,更加高效,但是正如其是元组类型,其内容以及值是不可变的。要修改任何属性,需要通过 namedtuple()
实例的 replace() 方法来实现。
该方法会创建一个全新的命名元组,并修改对应的属性的值:
s = Stock('ACME', 100, 123.45)
s.shares = 75
>>> AttributeError: can't set attribute
s = s._replace(shares=75)
print(s)