首页 > temp > python入门教程 >
-
1.18 映射名称到序列元素
问题描述
你有一段通过下标访问列表或元组中元素的代码,但是这样有时候会使得你的代码难以阅读,于是你想通过名称来访问元素。
解决方案
collections.namedtuple()
函数通过使用一个普通的元组对象来帮你解决这个问题。这个函数实际上是一个返回Python中标准元组类型子类的一个工厂方法。你需要传递一个类型名和你需要的字段给它,然后它就会返回一个类,你可以初始化这个类,为你定义的字段传递值等。例如:
from collections import namedtuple
Subscriber = namedtuple('Tester', ['addr', 'joined'])
sub = Subscriber('Abu11@cnblogs.com', '2022-01-07')
"""
sub = Tester(addr='Abu11@cnblogs.com', joined='2022-01-07')
sub.addr = Abu11@cnblogs.com
sub.joined = 2022-01-07
"""
尽管namedtuple
的实例看起来像一个普通的类实例,但是它跟元组类型是可交换的,支持所有的普通元组操作,比如索引和解压。例如:
length = len(sub)
addr, joined = sub
"""
length = 2
addr = 'Abu11@cnblogs.com'
joined = '2022-01-07'
"""
命名元组的一个主要用途是将你的代码从下标操作中解脱出来。因此,如果你通过下标去操作一个元组列表中的元素,当你在表中添加新的列的时候你的代码可能就会出错了。但是如果你使用了命名元组,就不会有这种问题。
为了说明这个问题,下面是使用普通元组的代码:
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
讨论
命名元组另一个作用就是作为字典的替代,因为字典存储需要更多的内存空间。如果你需要构建一个非常大的包含字典的数据结构,那么使用命名元组会更加高效。但是需要注意,一个命名元组是不可更改的。比如:
s = Stock('A', 1, 22) # Stock(name='A', shares=1, price=22)
s.shares = 7
"""
AttributeError: can't set attribute
"""
如果你真的需要改变属性的值,那么可以使用命名元组实例的_replace()
方法,它会创建一个全新的命名元组并将对应的字段用新值取代。例如:
s = s._replace(shares=7)
print(s)
"""输出结果:
Stock(name='A', shares=7, price=22)
"""
_replace()
方法还有一个很有用的特性就是当你的命名元组拥有可选或者缺失字段时,它是一个非常方便的填充数据的方法。你可以创建一个包含缺省值的原型元组,然后使用_replace()
方法创建新的值被更新过的实例。例如:
from collections import namedtuple
Stock = namedtuple('Stock', ['name', 'shares', 'price', 'date', 'time'])
stock_instance = Stock('', 0, 0.0, None, None)
def dict_to_stock(s):
return stock_instance._replace(**s)
if __name__ == '__main__':
a = {'name': 'ACME', 'shares': 100, 'price': 123.45}
print(dict_to_stock(a))
b = {'name': 'ACME', 'shares': 100, 'price': 123.45, 'date': '12/17/2012'}
print(dict_to_stock(b))
"""输出结果:
Stock(name='ACME', shares=100, price=123.45, date=None, time=None)
Stock(name='ACME', shares=100, price=123.45, date='12/17/2012', time=None)
"""
最后要说的是,如果你的目标是定义一个需要更新很多实例属性的高效数据结构,那么命名元组并不是最佳选择。这时候你应该考虑定义一个包含__slots__
方法的类(参考8.4小节)
总结
本小节介绍了collections.namedtuple()
方法,它可以初始化一个类,将一个元组的值依次赋予给类的各字段,这样就可以通过字段访问值。一定程度上可以替代字典。
原文:https://www.cnblogs.com/L999C/p/15776734.html