python namedtuple

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

from collections import namedtuple


Subscriber = namedtuple('Subscriber', ['addr', 'joined'])
sub = Subscriber('jonesy@example.com', '2012-10-19')
print(sub)
print(sub.addr)

尽管 namedtuple 的实例看起来像一个普通的类实例,但是它跟元组类型是可交换的,支持所有的普通元组操作,比如索引和解压。比如:

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

命名元组的一个主要用途是将你的代码从下标操作中解脱出来。因此,如果你从数据库调用中返回了一个很大的元组列表,通过下标去操作其中的元素,当你在表中添加了新的列的时候你的代码可能就会出错了。但是如果你使用了命名元组,那么就不会有这样的顾虑。为了说明清楚,下面是使用普通元组的代码:

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

下标操作通常会让代码表意不清晰,并且非常依赖记录的结构。下面是使用命名元组的版本:

Stock = namedtuple('Stock', ['name', 'shares', 'price'])


def new_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)
# s.shares = 75

如果你真的需要改变然后的属性, 那么可以使用命名元组实例的 replace() 方法,它会创建一个全新的命名元组并将对应的字段用新的值取代。比如:

s = s._replace(shares=75)
print(s)

_replace() 方法还有一个很有用的特性就是当你的命名元组拥有可选或者缺失字段时候,它是一个非常方便的填充数据的方法。你可以先创建一个包含缺省值的原型元组,然后使用 replace() 方法创建新的值被更新过的实例。比如:

Stock1 = namedtuple('Stock', ['name', 'shares', 'price', 'date', 'time'])

stock_prototype = Stock1('', 0, 0.0, None, None)


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


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))

最后要说的是,如果你的目标是定义一个需要更新很多实例属性的高效数据结构,那么命名元组并不是你的最佳选择。这时候你应该考虑定义一个包含 slots 方法的类.

### Python 中 `namedtuple` 的使用方法 #### 创建命名元组 创建命名元组的方式有两种主要形式。一种是通过继承方式定义类,另一种是直接调用 `collections.namedtuple()` 方法。 ```python from collections import namedtuple # 定义一个名为 Point 的 named tuple 类型 Point = namedtuple('Point', ['x', 'y']) p = Point(11, y=22) print(p[0] + p[1]) # 输出数值相加的结果[^1] print(p.x + p.y) # 使用属性访问成员数据 ``` 两种定义 `namedtuple` 的语法被认为是等价的: ```python from typing import NamedTuple class Employee(NamedTuple): name: str id: int Employee = namedtuple('Employee', ['name', 'id']) ``` 上述两段代码可以互换使用并达到相同的效果[^2]。 #### 增强功能与灵活性 为了增加更多特性,比如设置默认值给某些字段,在定义时可以通过 `_fields_defaults` 参数来实现这一点: ```python Node = namedtuple('Node', ['value', 'left', 'right'], defaults=[None, None]) node = Node(value='root') print(node.left is node.right is None) # True ``` 此实例展示了如何利用 `defaults` 参数简化对象初始化过程中的参数传递需求[^4]。 #### 子类化字符串以增强功能性 虽然这不是 `namedtuple` 特有的概念,但在实际应用中经常遇到需要扩展内置类型的场景。对于字符串而言,可以通过包装的方式来实现在不改变原有行为的基础上添加新能力的目的[^3]: ```python class TaggedString(str): tag = "default" ts = TaggedString("example text") print(ts.tag) ``` 尽管这段代码不是严格意义上的 `namedtuple` 应用案例,但它体现了类似的模式——即基于现有结构构建更复杂的数据模型。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值