Python 输入 TypeVar(A, B, covariant=True) 是什么意思?

Int*_*rer 17 python oop static-typing covariance mypy

今天我深入研究了 Liskov 的替换原则和协方差/逆变。

我被困在以下之间的区别上:

  1. T = TypeVar("T", bound=Union[A, B])
  2. T = TypeVar("T", A, B, covariant=True)

我对#1 的理解

TypeVar('T', A, B) 和 TypeVar('T', bound=Union[A, B]) 的区别

这个答案明确指出T可以是:

  1. Union[A, B](或任何亚型的联合ABUnion[A, BChild]
  2. A(或 的任何子类型A
  3. B(或 的任何子类型B

这对我来说很有意义。


有缺陷的理解#2

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

重新提及bound=Union[A, B]案例,但没有理解选项#2 的含义,A, B, covariant=True

我试过玩弄mypy,但似乎无法弄清楚。 谁能指出这是什么意思?

认为这意味着:

  1. A(或 的任何子类型A
  2. B(或 的任何子类型B

(又名它排除了Union上面的情况)


**编辑**

在评论中被问到:

你确定它们真的不同吗?

这是显示差异的示例代码。错误来自mypy==0.770.

from typing import Union, TypeVar, Generic


class A: pass

class ASub(A): pass

class B: pass


# Case 1... Success: no issues found
# T = TypeVar("T", bound=Union[A, B])

# Case 2... error: Value of type variable "T" of "SomeGeneric" cannot be "ASub"
T = TypeVar("T", A, B, covariant=True)


class SomeGeneric(Generic[T]): pass

class SomeGenericASub(SomeGeneric[ASub]): pass
Run Code Online (Sandbox Code Playgroud)

**编辑 2**

我最终在python/mypy #8806 中询问了这个问题:当 T_co = TypeVar("T_co", A, B, covariant=True) 并传递 A 的子类时,Generic[T_co] 出错

这消除了我的一些误解。事实证明TypeVar("T", A, B, covariant=True)并不是真的正确,知道值限制A并且B实际上不是协变的。

covariant=True语法的使用只有在它们相关时才有用。

Roy*_*012 15

协方差和逆变是与面向对象和泛型之间的交集相关的术语。

这是这个概念试图回答的问题:

  1. 我们有几个“常规”、“面向对象”类BaseDerived.
  2. 我们还有一些泛型类型——比如说List<T>.
  3. 我们知道 Derived 可以在任何 base 可以使用的地方使用——这是否意味着List<Derived>可以在任何地方使用List<Base>
  4. 可以反过来吗?也许它是相反的方向,现在List<Base>可以在任何地方使用List<Derived>

如果(3)的答案是肯定的,则称为协方差,我们会说声明List为具有covariance=True。如果 (4) 的答案为真,则称为“逆方差”。如果没有一个是真的,它是不变的。

边界也来自 OO 和泛型的交集。当我们定义一个泛型类型 MyType 时 - 这是否意味着 'T' 可以是任何类型?或者,我可以对 T 可能是什么施加一些限制吗?Bounds 允许我声明 T 的上限是,例如, class Derived。在这种情况下,Base不能与 'MyType' 一起使用 - 但Derived它的所有子类都可以。

协方差和逆变的定义可以在PEP-484 的这一节中找到。