Ответ 1
Способ создания именованных кортежей делает наследование от классов 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, но вы можете pip install dataclasses
задний порт в Python 3.6.
Выше определены два неизменных класса с атрибутами 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
.