MyPy 不允许受约束的 TypeVar 是协变的?定义具有约束但协变的键值类型的通用字典

Pra*_*wal 2 generics covariance python-3.x mypy

我正在尝试定义一个自定义的通用 dict,它的键是 type T_key,值是 type T_val
我还想对T_keyand施加约束T_val,这样T_key只能是类型AorB或它们的子类。

我该如何实现?

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]
Run Code Online (Sandbox Code Playgroud)

当我尝试检查这一点时,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"
Run Code Online (Sandbox Code Playgroud)

我不明白为什么即使指定了Asub也不是有效类型。T_keycovariant=True

我在这里缺少什么?

mypy 版本:0.630

use*_*ica 5

这不是协方差的意思。对于协变类型变量T和泛型类Foo[T], 的实例Foo[Subclass]也被视为 的实例Foo[Superclass]。协方差对可以替代的类型没有影响T

如果你B被定义为

class B(A): ...
Run Code Online (Sandbox Code Playgroud)

代替

class B: ...
Run Code Online (Sandbox Code Playgroud)

,那么由于协方差MyDict[B, B],类型MyDict[A, A]的值将被静态类型检查器视为有效的类型值。您仍然无法创建 type 的值MyDict[ASub, BSub],因为您的类型变量的唯一有效值是AB

您正在寻找的概念是有界类型变量,使用bound关键字参数,而不是约束类型变量。看起来您可以将联合指定为边界,这让我感到非常惊讶,因此将类型变量声明为

T_key = TypeVar('T_key', bound=Union[A, B])
T_val = TypeVar('T_val', bound=Union[A, B])
Run Code Online (Sandbox Code Playgroud)

应该管用。