我正在尝试提出一个通用的
TypeVar
解决方案,以避免创建不断扩展的 Union
类型注释。这是我目前所拥有的有点人为的 MRE:
from __future__ import annotations
from typing import Union
class CreatedDetails:
def __init__(self, creator: Union[Creator1, Creator2], new: bool) -> None:
self.creator = creator
self.new = new
class Creator1:
def __init__(self) -> None:
self.name = "creator1"
def create(self) -> CreatedDetails:
return CreatedDetails(creator=self, new=True)
class Creator2:
def __init__(self) -> None:
self.name = "creator2"
def create(self) -> CreatedDetails:
return CreatedDetails(creator=self, new=False)
creator1 = Creator1()
created = creator1.create()
created.creator.name
这很不错,我的类型检查器可以识别一切:
但是,这依赖于我向
Creator
类型注释添加新的 Ùnion
类。
我尝试过使用通用的
TypeVar
:
from __future__ import annotations
from typing import TypeVar
CreatorRecord = TypeVar("CreatorRecord")
class CreatedDetails:
def __init__(self, creator: CreatorRecord, new: bool) -> None:
self.creator = creator
self.new = new
class Creator:
pass
class Creator1(Creator):
def __init__(self) -> None:
self.foo = "foo"
def create(self) -> CreatedDetails:
return CreatedDetails(creator=self, new=True)
class Creator2(Creator):
def __init__(self) -> None:
self.bar = "bar"
def create(self) -> CreatedDetails:
return CreatedDetails(creator=self, new=False)
creator1 = Creator1()
created = creator1.create()
created.creator.foo
created.new
但是,类型检查器并不能完全识别这一点:
我哪里出错了?
CreatedDetails
本身必须是通用的。如果类型检查器只知道 created
是 CreatedDetails
的实例,则不足以告诉创建它的创建者的特定类型。但通过正确的注释,CreatedDetails[Creator1]
类型可以提供该信息。
您已经创建了一个泛型构造函数,但您真正需要的是一个泛型类:
from typing import TypeVar, Generic
Creator = TypeVar("Creator")
class CreatedDetails(Generic[Creator]):
creator: Creator
new: bool
def __init__(self, creator: Creator, new: bool) -> None:
self.creator = creator
self.new = new
class Creator1:
def __init__(self) -> None:
self.foo = "foo"
def create(self) -> CreatedDetails['Creator1']:
return CreatedDetails(creator=self, new=True)
class Creator2:
def __init__(self) -> None:
self.bar = "bar"
def create(self) -> CreatedDetails['Creator2']:
return CreatedDetails(creator=self, new=False)