命名元组的构造方式使得从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.