将先前字段中的字段添加到 NamedTuple

Sea*_*123 6 python namedtuple python-3.x

假设我想存储一些有关会议日程的信息,包括演示时间和暂停时间。我可以在NamedTuple.

from typing import NamedTuple

class BlockTime(NamedTuple):
    t_present: float
    t_pause: float
Run Code Online (Sandbox Code Playgroud)

但是,如果我还想存储每个块将占用多少t_each = t_pause + t_present,我不能只将其添加为属性:

class BlockTime(NamedTuple):
    t_present: float
    t_pause: float
    # this causes an error
    t_each = t_present + t_pause
Run Code Online (Sandbox Code Playgroud)

在 Python 中执行此操作的正确方法是什么?如果我创建一个__init__(self)方法并将其作为实例变量存储在那里,但它是可变的。

MSe*_*ert 4

如果它没有真正存储而是动态计算就可以了,您可以使用一个简单的property方法。

from typing import NamedTuple

class BlockTime(NamedTuple):
    t_present: float
    t_pause: float
    @property
    def t_each(self):
        return self.t_present + self.t_pause

>>> b = BlockTime(10, 20)
>>> b.t_each  # only available as property, not in the representation nor by indexing or iterating
30
Run Code Online (Sandbox Code Playgroud)

这样做的优点是您永远不会(甚至不会意外)为其存储错误的值。然而,代价是根本不实际存储它。因此,为了看起来好像它已被存储,您至少必须重写__getitem__, __iter____repr__这可能太麻烦了。

例如,NamedTuplePatrick Haugh 给出的方法有一个缺点,即仍然可能创建不一致的BlockTimes 或失去部分便利namedtuple性:

>>> b = BlockTime.factory(1.0, 2.0)
>>> b._replace(t_present=20)
BlockTime(t_present=20, t_pause=2.0, t_each=3.0)

>>> b._make([1, 2])
TypeError: Expected 3 arguments, got 2
Run Code Online (Sandbox Code Playgroud)

事实上,您实际上有一个必须与其他字段同步的“计算”字段,这一事实已经表明您可能根本不应该存储它以避免状态不一致。