我正在尝试定义一个自定义的通用dict,其键的类型为T_key
,而值的类型为T_val
。
我还想对T_key
和T_val
设置约束,以使T_key
只能是A
或B
或它们的子类类型。
我如何做到这一点?
from typing import TypeVar, Generic
class A: ...
class B: ...
class Asub(A): ...
class Bsub(B): ...
T_key = TypeVar('T_key', A, B, covariant=True)
T_val = TypeVar('T_val', A, B, covariant=True)
class MyDict(Generic[T_key, T_val]): ...
w: MyDict[ A, B]
x: MyDict[ A, Bsub]
y: MyDict[Asub, B]
z: MyDict[Asub, Bsub]
当我尝试检查时,mypy在x
,y
和z
的注释中给出了错误。只有w
的注释才能正常工作。
generic.py:17: error: Value of type variable "T_val" of "MyDict" cannot be "Bsub"
generic.py:18: error: Value of type variable "T_key" of "MyDict" cannot be "Asub"
generic.py:19: error: Value of type variable "T_key" of "MyDict" cannot be "Asub"
generic.py:19: error: Value of type variable "T_val" of "MyDict" cannot be "Bsub"
即使指定了Asub
,我也不明白T_key
为何不是covariant=True
的有效类型。
我在这里想念什么?
mypy版本:0.630
答案 0 :(得分:3)
协方差不是这个意思。使用协变量类型变量T
和通用类Foo[T]
,Foo[Subclass]
的实例也被视为Foo[Superclass]
的实例。协方差对T
可以替代哪些类型没有影响。
如果您的B
是A
的子类,则静态类型检查器会将MyDict[B, B]
类型的值也视为MyDict[A, A]
类型的值,因为协方差。您仍将无法创建类型MyDict[C, C]
的值,其中C
是B
或A
的其他子类。
您要寻找的概念是 bounded 类型变量,使用bound
关键字参数,而不是约束类型变量。看起来您可以指定联合作为边界,这让我很惊讶,因此将类型变量声明为
T_key = TypeVar('T_key', bound=Union[A, B])
T_val = TypeVar('T_val', bound=Union[A, B])
应该工作。
答案 1 :(得分:1)
结果显示绑定可以接受联合。
from typing import TypeVar, Generic, Union
class A: ...
class B: ...
class Asub(A): ...
class Bsub(B): ...
T_key = TypeVar('T_key', bound=Union[A, B])
T_val = TypeVar('T_val', bound=Union[A, B])
class MyDict(Generic[T_key, T_val]): ...
w: MyDict[ A, B] # passes
x: MyDict[ A, Bsub] # passes
y: MyDict[Asub, B] # passes
z: MyDict[Asub, Bsub] # passes
bad: MyDict[int, int] # Type argument "builtins.int" of "MyDict" must be a subtype of "Union[generic.A, generic.B]"