今天我深入研究了里氏替换原理和协变/逆变。
我陷入了以下两者之间的区别:
T = TypeVar("T", bound=Union[A, B])
T = TypeVar("T", A, B, covariant=True)
我对#1的理解
TypeVar('T', A, B) 和 TypeVar('T',bound=Union[A, B]) 之间的区别
这个答案清楚地表明了
T
可以是:
(或Union[A, B]
和A
的任何子类型的联合,例如B
)Union[A, BChild]
(或A
的任何子类型)A
(或B
的任何子类型)B
这对我来说非常有意义。
我对#2的有缺陷的理解
MyPy 不允许受约束的 TypeVar 是协变的?使用受约束但协变的键值类型定义通用字典
重新提到
bound=Union[A, B]
案例,但没有理解选项#2的含义,A, B, covariant=True
。
我尝试过使用
mypy
,但似乎无法弄清楚。
谁能指出这是什么意思?
我认为这意味着:
A
(或 A
的任何子类型)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
**编辑2**
这消除了我的一些误解。 事实证明
TypeVar("T", A, B, covariant=True)
并不真正正确,因为知道值限制 A
和 B
实际上并不是协变的。
使用
covariant=True
语法仅在它们相关时才有用。
协变和逆变是与面向对象和泛型之间的交集相关的术语。
这是这个概念试图回答的问题:
Base
和Derived
。List[T]
。Derived
可以在任何 Base
可以使用的地方使用 - 这是否意味着 List[Derived]
可以在任何 List[Base]
可以使用的地方使用?List[Base]
可以用在任何 List[Derived]
可以用的地方?如果(3)的答案是肯定的,则称为 协方差,我们会说声明
List
具有 covariance=True
。如果 (4) 的答案为真,则称为 contra-variance。如果没有一个为真,则它是不变。
界限也来自面向对象和泛型的交集。当我们定义泛型类型
MyType<T>
时,是否意味着 T
可以是任何类型?或者,我可以对 T
施加一些限制吗?边界允许我声明 T
的上限是,例如,类 Derived
。在这种情况下,Base
不能与 MyType
一起使用 - 但 Derived
及其所有子类可以。
协变和逆变的定义可以在PEP-484的这一部分找到。