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

时间:2018-10-25 20:39:00

标签: python-3.x generics covariance mypy

我正在尝试定义一个自定义的通用dict,其键的类型为T_key,而值的类型为T_val
我还想对T_keyT_val设置约束,以使T_key只能是AB或它们的子类类型。

我如何做到这一点?

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在xyz的注释中给出了错误。只有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

2 个答案:

答案 0 :(得分:3)

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

如果您的BA的子类,则静态类型检查器会将MyDict[B, B]类型的值也视为MyDict[A, A]类型的值,因为协方差。您仍将无法创建类型MyDict[C, C]的值,其中CBA的其他子类。

您要寻找的概念是 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]"