【发布时间】:2020-09-17 05:29:27
【问题描述】:
我有一个 Document 和 Page 类型,都包含数据和元数据部分。它们看起来一样:
class Document:
__data: DocumentData
__meta: DocumentMeta
def __init__(self, part: Union[DocumentData, DocumentMeta, None] = None, data: Optional[DocumentData] = None,
meta: Optional[DocumentMeta] = None):
super().__init__()
self.data: Optional[DocumentData] = data
self.meta: Optional[DocumentMeta] = meta
if part is not None:
if type(part) == DocumentData:
data = part
meta = DocumentMeta()
elif type(part) == DocumentMeta:
meta = part
data = DocumentData()
class Page:
__data: PageData
__meta: PageMeta
def __init__(self, part: Union[PageData, PageMeta, None] = None, data: Optional[PageData] = None,
meta: Optional[PageMeta] = None):
super().__init__()
self.data: Optional[PageData] = data
self.meta: Optional[PageMeta] = meta
if part is not None:
if type(part) == PageData:
data = part
meta = PageMeta()
elif type(part) == PageMeta:
meta = part
data = PageData()
我现在想重构这两种类型以使用泛型类型。我是这样做的:
from typing import Generic, Optional, TypeVar, Union
DataStruct = TypeVar('DataStruct')
MetaStruct = TypeVar('MetaStruct')
class MetaDataStruct(Generic[DataStruct, MetaStruct]):
__data: DataStruct
__meta: MetaStruct
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 type(part) == DataStruct:
data = part
meta = MetaStruct()
elif type(part) == MetaStruct:
meta = part
data = DataStruct()
class DocumentData:
pass
class DocumentMeta:
pass
class PageData:
pass
class PageMeta:
pass
class Document(MetaDataStruct[DocumentData, DocumentMeta]):
pass
class Page(MetaDataStruct[PageData, PageMeta]):
pass
现在类型检查几乎没有问题。
-
如果 type(part) == DataStruct: 一直返回 False。在运行时,类型(部分)是以下之一:DocumentData、DocumentMeta、PageData、PageMeta。我知道我必须将 type(part) 与 DataStruct 的实际类型进行比较。解决 DataStruct 的运行时类型的正确方法是什么?
在python hints manual 中写道:在运行时,isinstance(x, T) 将引发 TypeError。一般来说,isinstance() 和 issubclass() 不应该与类型一起使用。 我相信这里也有同样的问题。我可以使用 type(self).orig_bases[0].args[0] 来推断 DataStruct,但它在概念上是不正确的.它将检索第一个通用参数而不是 DataStruct。因此,如果 MetaDataStruct 基类签名将更改为 class MergedStruct(Struct, Generic[MetaStruct, DataStruct])(交换的 TypeVar 参数),则将检索 MetaStruct 而不是 DataStruct。
由于某种原因,当我尝试初始化 Document(part=1) 时,它通过了。在实践中,我希望代码会引发 TypeError。
【问题讨论】:
标签: python generics types subclass type-hinting