键入.NamedTuple带着一本字典

2024-09-25 02:29:34 发布

您现在位置:Python中文网/ 问答频道 /正文

我尝试创建一个NamedTuple,其中一个字段默认为空字典。这主要起作用,但是默认值在NamedTuple的实例之间共享:

from typing import NamedTuple, Dict

class MyTuple(NamedTuple):
    foo: int
    bar: Dict[str, str] = {}


t1 = MyTuple(1, {})
t2 = MyTuple(2)
t3 = MyTuple(3)

t2.bar["test2"] = "t2"
t3.bar["test3"] = "t3"

print(t2)  # MyTuple(foo=2, bar={'test2': 't2', 'test3': 't3'})
print(t3)  # MyTuple(foo=3, bar={'test2': 't2', 'test3': 't3'})
assert "test3" not in t2.bar  # raises

如何确保bar字段是每个实例的新dict?PEP-526中的所有dict示例似乎都使用ClassVar,但这与我在这里想要的正好相反。你知道吗

我可以在这里使用带有default factory function(或attrs中的等效项)的数据类,但我目前需要支持python3.6.x和3.7.x,这样会增加一些开销。你知道吗

值得一提的是,我测试的python版本是3.7.3


Tags: 实例from字典foobarnamedtupledictt3
1条回答
网友
1楼 · 发布于 2024-09-25 02:29:34

typing.NamedTuple/collections.namedtuple不支持工厂函数,并且实现默认值的机制看起来不可能以任何合理的方式重载。也不能通过直接编写自己的__new__来手动实现这样的默认值。你知道吗

在aict中,唯一半合理的方法是编写一个namedtuple的子类,它实现自己的__new__,以编程方式生成默认值:

class MyTuple(NamedTuple):
    foo: int
    bar: Dict[str, str] = {}  # You can continue to declare the default, even though you never use it

class MyTuple(MyTuple):
    __slots__ = ()
    def __new__(cls, foo, bar=None):
        if bar is None:
            bar = {}
        return super().__new__(cls, foo, bar)

开销相对较小,但它确实涉及到六行样板文件。您可以将样板文件(以可能过于密集的代码为代价)从父级MyTuple的定义减少一行到最终MyTuple的定义中,以减少冗长性,例如:

class MyTuple(typing.NamedTuple('MyTuple', [('foo', int), ('bar', Dict[str, str])])):
    __slots__ = ()
    def __new__(cls, foo, bar=None):
        if bar is None:
            bar = {}
        return super().__new__(cls, foo, bar)

但这仍然会形成继承层次结构,而不仅仅是tuple类的单个直接后代,就像从NamedTuple继承一样。这不应该对性能产生有意义的影响,只是需要注意一些事情。你知道吗

相关问题 更多 >