命名元组的构造方式使得从typing.NamedTuple
类继承是不可能的。您必须编写自己的元类来扩展typing.NamedTupleMeta
该类以使子类化工作,即使那样生成的类collections.namedtuple()
也不是为扩展而构建的。
相反,您想使用新dataclasses
模块来定义您的类并实现继承:
from dataclasses import dataclass
@dataclass(frozen=True)
class Base:
x: int
y: int
@dataclass(frozen=True)
class BaseExtended(Base):
z: str
该模块是 Python 3.7 中的新模块,但您可以在 Python 3.6 上pip install dataclasses
向后移植。
上面定义了两个具有x
和y
属性的不可变类,BaseExtended
该类又添加了一个属性。BaseExtended
是 的完整子类Base
,因此出于打字目的,它符合DoSomething()
函数的要求。
这些类不是完整命名的元组,因为它们没有长度或支持索引,但是通过创建一个继承自的基类collections.abc.Sequence
,添加两个方法来按索引访问字段,这很容易添加。如果您添加order=True
到@dataclass()
装饰器,那么您的实例将变得完全可排序,就像(命名)元组一样:
from collections.abc import Sequence
from dataclasses import dataclass, fields
class DataclassSequence(Sequence):
# make a dataclass tuple-like by accessing fields by index
def __getitem__(self, i):
return getattr(self, fields(self)[i].name)
def __len__(self):
return len(fields(self))
@dataclass(frozen=True, order=True)
class Base(DataclassSequence):
x: int
y: int
MyPy很快就会dataclasses
明确支持;在 0.600 版本中,您仍然会收到错误,因为它无法识别dataclasses
模块导入或__new__
生成方法。
在 Python 3.6 及更早的版本中,也可以安装attrs
项目来达到同样的效果;上面的序列基类看起来像这样使用attrs
:
from collections.abc import Sequence
import attr
class AttrsSequence(Sequence):
# make a dataclass tuple-like by accessing fields by index
def __getitem__(self, i):
return getattr(self, attr.fields(type(self))[i].name)
def __len__(self):
return len(attr.fields(type(self)))
@attr.s(frozen=True, auto_attribs=True)
class Base(AttrsSequence):
x: int
y: int
dataclasses
直接基于attrs
,attrs
提供更多功能;mypy 完全支持使用attrs
.