问题
通过下标访问列表或元组中的元素,代码可读性不强,可以通过名称来访问元素。
解决方案
collections.namedtuple() 函数是继承自tuple的子类。可以创建自定义元素个数的tuple对象,它具备tuple的不变性,又可以根据属性而不是索引来引用其中的元素。代码示例:
from collections import namedtuple
User = namedtuple('User', ['mail_add', 'joined_date'])
print(User)
user = User('python@gmail.com', '2017-11-10')
print(user)
print(user.mail_add)
print(user.joined_date)
User(mail_add='python@gmail.com', joined_date='2017-11-10')
python@gmail.com
2017-11-10
尽管 namedtuple 的实例看起来像一个普通的类实例,但是它跟元组类型是可交换的,支持所有的普通元组操作,如索引和解压。 比如:
print(len(user))
mail, joined = user
print(mail)
print(joined)
2
python@gmail.com
2017-11-10
命名元组的主要用途是将代码从下标操作中解脱出来。 因此,如果在数据库调用中返回了一个很大的元组列表,通过下标去操作其中的元素, 当数据库表中添加了新的列时,代码可能就会出错,但如果使用了命名元组,就不会有这样的顾虑。
为了说明清楚,下面是使用普通元组的代码:
def cumputer_cost(records):
total = 0.0
for record in records:
total += record[1] * record[2]
return total
下标操作通常会让代码表意不清晰,并且非常依赖记录的结构。 下面是使用命名元组的版本:
from collections import namedtuple
Stock = namedtuple('Stock', ['name', 'shares', 'price'])
def cumputer_cost(records):
total = 0.0
for record in records:
r = Stock(*record)
total += s.shares * s.price
return total
讨论
命名元组另一个用途是作为字典的替代,因为字典存储需要更多的内存空间。 如果需要构建一个非常大的包含字典的数据结构,那么使用命名元组会更加高效。 但是需要注意的是,不像字典那样,一个命名元组是不可更改的。比如:
s = Stock('ACME', 100, 123.45)
s.shares = 75
Traceback (most recent call last):
File "", line 1, in
s.shares = 75
AttributeError: can't set attribute
如果确实需要改变属性的值,可以使用命名元组实例的 _replace() 方法, 它会创建一个全新的命名元组,并将对应的字段用新的值取代。比如:
s = Stock('ACME', 100, 123.45)
s = s._replace(shares=75)
print(s)
Stock(name='ACME', shares=75, price=123.45)
最后要说的是,如果目标是定义一个需要更新很多实例属性的高效数据结构,那么命名元组并不是最佳选择。 这时候应该考虑定义一个包含 slots 方法的类。