Python实用技法第17篇:将名称映射到序列的元素中

上一篇文章: Python实用技法第16篇:从字典中提取子集
下一篇文章: Python实用技法第18篇:同时对数据作转换和换算

一、需求🙀

咱们的代码是经过位置(即索引或下标)来访问列表会元组的,但有时候这会让代码变得有些难以阅读。咱们但愿能够经过名称来访问元素,以此减小结构中对位置的依赖性。

二、解决方案😸

相比普通的元组,collections.namedtuple()(命名元组)只增长了极少的开销就提供了这些便利。实际上collections.namedtuple()是一个工厂方法,它返回的是Python中标准元组类型的子类。咱们提供给它一个类型名称以及相应的字段,它就返回一个可实例化的类、为你已经定义好的字段传入值等。数据库

from collections import namedtuple
Subscriber=namedtuple('Subsciber',['addr','joined'])
sub=Subscriber("1782980833@qq.com","2018-10-23")

print(sub)
print(sub.addr)
print(sub.joined)

print(len(sub))
addr,joined=sub
print(addr)
print(joined)

#下面错误,由于namedtuple是不可变的
#sub.joined="2019"

结果:segmentfault

Subsciber(addr='1782980833@qq.com', joined='2018-10-23')
1782980833@qq.com
2018-10-23
2
1782980833@qq.com
2018-10-23

尽管namedtuple的实例看起来就像一个普通的类实例,但它的实例与普通的元组是可互换的,并且支持全部普通元组所支持的操做。数组

命名元组的主要做用在于将代码同它所控制的元素位置间解耦。因此,若是从数据库调用中获得了一个大型的元组列表,并且经过元素的位置来访问元素,那么假如在表单中新增了一列数据,那么代码就会崩溃,但若是首先将返回的元组转换为命名元组,就不会出现问题。数据结构

为了说明这个问题,下面有一些使用普通元组的代码:设计

def compute_cost(records):
    total=0.0
    for rec in records:
        total+=rec[1]*rec[2]
    return total

经过位置来引用元素经常使得代码的表达力不够强,并且也很依赖于记录的具体结构。code

下面是使用命名元组的版本:索引

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

三、分析😈

namedtuple的一种可能用法是做为字典的替代,后者须要更多的空间来存储。所以,若是要构建设计字典的大型数据,使用namedtuple会更加高效,可是请注意,与字典不一样的是,namedtuple是不可变的。ci

若是须要修改任何属性,能够经过使用namedtuple实例_replace()方法来实现。该方法会建立一个全新的命名元组,并对相应的值作替换。get

from collections import namedtuple
Subscriber=namedtuple('Subsciber',['addr','joined'])
sub=Subscriber("1782980833@qq.com","2018-10-23")

print(sub)

sub=sub._replace(joined="2018-10-24")
print(sub)

结果:原型

Subsciber(addr='1782980833@qq.com', joined='2018-10-23')
Subsciber(addr='1782980833@qq.com', joined='2018-10-24')

_replace()方法有一个微妙的用途,那就是它能够做为一种简单的方法填充具备可选或缺失字段的命名元组。要作到这点,首先建立一个包含默认值得原型数组,而后使用_replace()方法建立一个新的实例,把相应的值替换掉。

from collections import namedtuple
Subscriber=namedtuple('Subsciber',['addr','joined','age'])
sub=Subscriber("",None,0)

def dict_to_stock(s):
    return sub._replace(**s)

a={"addr":"111111@qq.com","joined":"1111-11-11","age":11}
a=dict_to_stock(a)
print(a)

b={"addr":"111111@qq.com","joined":"1111-11-11"}
b=dict_to_stock(b)
print(b)

结果:

Subsciber(addr='111111@qq.com', joined='1111-11-11', age=11)
Subsciber(addr='111111@qq.com', joined='1111-11-11', age=0)

最后,也是至关重要的是,应该要注意若是咱们的目标是定义一个高效的数据结构,并且未来会修改各类实例属性,那么使用namedtuple并非最佳选择,相反,能够考虑顶一个使用了__slots__属性的类。

上一篇文章: Python实用技法第16篇:从字典中提取子集
下一篇文章: Python实用技法第18篇:同时对数据作转换和换算
相关文章
相关标签/搜索