Python 使用字典默认值键入.NamedTuple
我试图创建一个NamedTuple,其中一个字段默认为空字典。这主要起作用,但是默认值在NamedTuple的实例之间共享:Python 使用字典默认值键入.NamedTuple,python,namedtuple,Python,Namedtuple,我试图创建一个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.
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
如何确保每个实例的栏
字段都是新的dict?中的所有dicts示例似乎都使用ClassVar,但这与我想要的正好相反
我可以在这里使用带有(或attrs中的等效项)的dataclass,但我目前需要支持python 3.6.x和3.7.x,因此这会增加一些开销
值得一提的是,我正在测试的python版本是3.7.3,键入。NamedTuple/
集合。NamedTuple
不支持工厂函数,实现默认值的机制看起来也不以任何合理的方式重载。您也不能通过直接编写自己的\uuuu new\uuu
来手动实现这种默认设置
在AICT中,唯一半合理的方法是编写一个名为tuple的的子类,它实现自己的\uuuu new\uuuu
,以编程方式生成默认值:
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)
但这仍然会形成一个继承层次结构,而不仅仅是元组
类的一个直接后代,就像从NamedTuple
继承一样。这不应该对性能产生有意义的影响,只是需要注意