python cookbook 学习笔记 第一章 数据结构和算法(17)映射名称到序列元素

  • 映射名称到序列元素
  • 问题:
    • 有一段通过下标访问列表或者元组中元素的代码,但是这样有时候会使代码难以阅读,于是想通过名称来访问 元素。
  • 解决方案:
    • collections.namedtuple() 函数通过使用一个普通的元组对象来解决这个问题。这个函数实际上是返回 Python中标准元组类型子类的一个工厂方法。需要传递一个类型名和需要的字段给它,他就会返回一个类。 可以初始化这个类,为定义的字段传递值等。代码示范:
from collections import namedtuple

Subscriber = namedtuple("Subscriber",["addr","joined"])

sub = Subscriber("jonesy@example.com", "2012-10-19")
print(sub)  # Subscriber(addr='jonesy@example.com', joined='2012-10-19')

print(sub.addr)  # jonesy@example.com
print(sub.joined) # 2012-10-19
  • 尽管 namedtuple 的实例看起来像一个普通的类实例,但是它跟元组类型是可交换的,支持所有的普通元组 操作,比如索引和解压。比如:
print(len(sub))  # 2

addr, joined = sub

print(addr, joined) # jonesy@example.com 2012-10-19
  • 命名元组的一个主要用途是将你的代码从下标操作中解脱出来。因此,如果从数据库调用中返回了一个很大的# 元组列表,通过下标去操作其中的元素,当你在表中添加了新的列的时候,你的代码可能就会出错了。但是如# 果你使用了命名元组,那么就不会有这样的顾虑。 为了说明清楚,下面使用普通元组的代码:
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("ACME", 100,123.45)
print(s)  # Stock(name='ACME', shares=100, price=123.45)

s.shares = 75
"""
 运行时报错:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: can't set attribute
"""
  • 如果真的需要改变元组的属性,可以用使用命名元组实例的_replace()方法,它会创建一个全新的命名元组# 并将对应的字段用新的值取代。比如:
s = s._replace(shares = 75)
print(s)  # Stock(name='ACME', 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)

def dict_to_stock(s):
    return stock_prototype._replace(**s)
  • 下面是它的使用方法:
a = {"name": "ACME", "shares": 100, "price":123.45}
dict_to_stock(a)
# Stock(name='ACME', shares=100, price=123.45, date=None, time=None)

b = {"name": "ACME", "shares": 100, "price": 123.45, "date": "12/17/2012"}
dict_to_stock(b)
# Stock(name='ACME', shares=100, price=123.45, date='12/17/2012', time=None)
  • 最后要说的是,如果你的目标是定义一个需要更新很多实例属性的高效数据结构,那么命名元组并不是你最 佳的选择。这时候应该考虑定义一个包含__slots__方法的类。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值