Python не выполняет проверку типов во время выполнения; вам нужно использовать инструмент анализа stati c, например mypy
. Запуск mypy по указанному вами коду показывает следующие ошибки:
22: error: 'DataStruct' is a type variable and only valid in type context
23: error: Incompatible types in assignment (expression has type "Union[DataStruct, MetaStruct]", variable has type "Optional[DataStruct]")
24: error: 'MetaStruct' is a type variable and only valid in type context
25: error: 'MetaStruct' is a type variable and only valid in type context
26: error: Incompatible types in assignment (expression has type "Union[DataStruct, MetaStruct]", variable has type "Optional[MetaStruct]")
27: error: 'DataStruct' is a type variable and only valid in type context
Если вы добавите строку, пытающуюся инициализировать Document(part=1)
, вы не получите ошибки времени выполнения (в вашем коде нет ничего, что могло бы вызвать ошибку; ваш if/elif
будет просто бездействующим), но вы получите ошибку проверки типов от mypy, которая выглядит так:
54: error: Argument "part" to "Document" has incompatible type "int"; expected "Union[DocumentData, DocumentMeta, None]"
Проблема с type()
проверяет, что вы попытка сделать (и с эквивалентом isinstance
) заключается в том, что TypeVar
не имеет значения времени выполнения, поэтому вы не можете вызвать его как конструктор. См .: Создание экземпляра типа, который является TypeVar
Один из способов исправить это - потребовать, чтобы подкласс предоставлял фактические типы:
from abc import ABC, abstractclassmethod
from typing import Generic, Optional, Type, TypeVar, Union
DataStruct = TypeVar('DataStruct')
MetaStruct = TypeVar('MetaStruct')
class MetaDataStruct(Generic[DataStruct, MetaStruct], ABC):
@abstractclassmethod
def _data_type(cls) -> Type[DataStruct]:
pass
@abstractclassmethod
def _meta_type(cls) -> Type[MetaStruct]:
pass
def __init__(
self,
part: Union[DataStruct, MetaStruct, None] = None,
data: Optional[DataStruct] = None,
meta: Optional[MetaStruct] = None
):
super().__init__()
self.data: Optional[DataStruct] = data
self.meta: Optional[MetaStruct] = meta
if part is not None:
if isinstance(part, self._data_type()):
data = part
meta = self._meta_type()()
elif isinstance(part, self._meta_type()):
meta = part
data = self._data_type()()
class DocumentData:
pass
class DocumentMeta:
pass
class Document(MetaDataStruct[DocumentData, DocumentMeta]):
@classmethod
def _data_type(cls) -> Type[DocumentData]:
return DocumentData
@classmethod
def _meta_type(cls) -> Type[DocumentMeta]:
return DocumentMeta
Вышеупомянутые проверки типов правильно (вы получите ошибки mypy, если не реализуете методы _data_type
и _meta_type
правильно в подклассе) и сможете использовать методы класса для вызова соответствующих конструкторов во время выполнения.