Python 3.x 有没有办法将工厂函数赋予`typing.NamedTuple`子类?
注意:我已经用Python3.6.7实现了这一点,但是那里的Python 3.x 有没有办法将工厂函数赋予`typing.NamedTuple`子类?,python-3.x,python-typing,Python 3.x,Python Typing,注意:我已经用Python3.6.7实现了这一点,但是那里的NamedTuple文档没有更改,所以我怀疑它是否会在那里更改 因此,我正在查看类型包中的类,我想知道是否有一种方法可以向其添加可变的默认值。第一次尝试是看我是否可以使用\u makeclassmethod来发挥我的优势,但是后来我发现该类检查了覆盖\u new\u (重述:如果将[]放入默认值,则每个对象都会共享相同的列表。对于旧的集合.namedtuple和新的键入.namedtuple,这就是集合.defaultdict类在构造函
NamedTuple
文档没有更改,所以我怀疑它是否会在那里更改
因此,我正在查看类型包中的类,我想知道是否有一种方法可以向其添加可变的默认值。第一次尝试是看我是否可以使用\u make
classmethod来发挥我的优势,但是后来我发现该类检查了覆盖\u new\u
(重述:如果将[]
放入默认值,则每个对象都会共享相同的列表。对于旧的集合.namedtuple
和新的键入.namedtuple
,这就是集合.defaultdict
类在构造函数中具有默认工厂
参数的原因。)
>>通过键入import NamedTuple,List
>>>班级人员(姓名为两人):
... 姓名:str
... 儿童:名单[“人”]
... 定义新(自我,姓名:str,子女:列表['Person']=None):
... 返回人。\u make(姓名,如果子女不是其他人,则为子女[])
...
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
文件“/usr/lib/python3.6/typing.py”,第2163行,新__
raise AttributeError(“无法覆盖NamedTuple属性”+键)
AttributeError:无法覆盖NamedTuple属性\uu新建__
>>>
我一直在琢磨如何在顽固的\uuuuuu new\uuuuuuu
中隐藏一个列表,但随后它开始变得毫无意义
>>> class Person(NamedTuple):
... name: str
... children: List['Person'] = None
...
>>>
>>> def new_new(name: str, children: List[Person] = None) -> Person:
... return Person(name, [] if children is None else children)
...
>>> old_new = Person.__new__
>>> def new_new(name: str, children: List[Person] = None) -> Person:
... return old_new(name, [] if children is None else children)
...
>>> Person.__new__ = new_new
>>>
>>> Person('John')
Person(name='John', children=None)
>>> Person.__new__
<function new_new at 0x7f776b2b2e18>
>>> new_new('John')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in new_new
File "<string>", line 14, in __new__
TypeError: tuple.__new__(X): X is not a type object (str)
>>> new_new(Person, 'John')
Person(name='John', children=None)
>>>
NamedTuple
仅提供类型检查的NamedTuple。命名为tupleMeta
覆盖\uuuuuuu新的
,\uuuuuuuuu初始化
和其他一些。你唯一的机会就是改变命名双工的工作方式
防止覆盖的保护本身不受保护。这允许您以各种方式对其进行修补
您可以从受保护的名称中删除\uuuu new\uuu
import typing
typing._prohibited = typing._prohibited[1:]
这允许您直接覆盖类中的\uuuu new\uuu
。
请注意,这将影响所有NamedTuple
子类型
您可以派生一个不保护\uuuu new\uuuu
的新元类,并将其用于您的NamedTuple
实例:
class NamedTupleUnprotectedMeta(typing.NamedTupleMeta):
def __new__(cls, typename, bases, ns):
...
# copy verbatim from NamedTupleMeta
...
# update from user namespace without protection
for key in ns:
if key not in typing._special and key not in nm_tpl._fields:
setattr(nm_tpl, key, ns[key])
return nm_tpl
class Person(NamedTuple, metaclass=NamedTupleUnprotectedMeta):
...
这允许您直接覆盖类中的\uuuu new\uuu
,而不影响NamedTuple
的其他子类型。请注意,还可以让元类添加一个自定义的new
,以调用类主体中设置的默认值
请注意,NamedTupleMeta
也会忽略base
,因此也不能使用mixin等。任何广泛的更改都需要先重写NamedTupleMeta
如果您只需要具有默认值的存储类,则和提供与您描述的内容匹配的声明:
@attr.s(auto_attribs=True)
class Person:
name: str
children: List['Person'] = attr.Factory(list)
这两个包都支持冻结,这类似于元组的不变性。虽然它不能严格回答您的问题,但支持类型检查和所需的默认参数工厂。不过,它不会创建一个NamedTuple。这可能是我将仔细研究的内容,然后尝试在任何地方使用,但正如你所说的,不是这个问题的答案。虽然,“它不是为了强大”也是一个完全正确的答案。请注意,人的行为是一致的。调用Person(*args)
相当于Person.\uuu new\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu(Person,*args)
,而不是Person.\u<代码>\uuuuuuuuuuuuuuuuuuuuuuuu
被默认元类type
调用,就像调用类方法一样。
@attr.s(auto_attribs=True)
class Person:
name: str
children: List['Person'] = attr.Factory(list)