我有以下(精简)数据类:
from dataclasses import dataclass
from typing import Union, Type
class BaseType: ...
class PathType(BaseType): ...
class DataType(BaseType): ...
_FinalTypes = Union[PathType, DataType]
@dataclass
class InterfaceInfo:
what: Type[_FinalTypes]
name: str
def __call__(self, *args, **kwargs) -> _FinalTypes:
return self.what(*args, **kwargs)
print(InterfaceInfo(PathType, "path"))
print(InterfaceInfo(DataType, "path"))
但是我不确定如何正确地注解它,我的目的实际上是无论您传入__init__
-方法的类型是什么,它都应该作为一个物化对象从__call__
中出来。
因为我现在所写的,类型检查器会认为有可能用PathType构造一个InterfaceInfo
,并从中产生一个DataType对象。
如果这是一个方法,我可以使用@overload
来输入提示它,但是这是一个类,所以我很困惑......我已经研究了绑定到BaseType的TypeVar。但是这不可能吗?或者类型检查器是否足够聪明,知道一个Type[PathType]进入,一个PathType需要出来?
我们该怎么解决这个问题呢?
谢谢!
1条答案
按热度按时间mznpcxlj1#
在某种程度上,可以通过将
InterfaceInfo
定义为what
类型的generic来解决这个问题,所以我认为您使用类型变量的想法是正确的。假设以下具体的
BaseType
子类型:我们用
BaseType
的上限定义类型变量,然后用该类型变量注解what
以及__call__
返回,如下所示:用法:
print
调用输出:mypy
输出:我们想要的和期待的。
我之所以在开头说“在某种程度上”,是因为
__call__
方法的签名显然只是一个廉价的解决方案,静态类型检查器无法验证我们在调用path_interface
或data_interface
时传递的参数是否与what
的类型兼容。我想了一会儿,但没有找到一个类型安全的解决方案,允许将
__call__
注解为泛型到 that 的程度。这意味着返回类型可能是安全的,但构造函数参数中没有安全性。也许其他人知道一种方法,或者Python类型系统不适合这样做。