函数参数逆变性的实用场景及基类方法适配疑问
函数子类型与实际场景疑问
我们知道,对于函数类型 T₁→T₂ 和 S₁→S₂,T₁→T₂ 是 S₁→S₂ 的子类型,当且仅当 S₁ 是 T₁ 的子类型,且 T₂ 是 S₂ 的子类型。但我想不出需要满足S₁≤T₁的实际场景,因为我们通常更倾向于用模板/泛型来规避里氏替换原则的限制。
先定义几个Python类作为讨论基础:
class Animal: ... class Cat(Animal): ... class Habitat: ... class Forest(Habitat): ...
假设我们有“研究中心”类,负责为动物寻找栖息地。下面的写法无法正常运行:
class AnimalResearchCenter: def find_habitat(self, a: Animal) -> Habitat: ... class CatResearchCenter(AnimalResearchCenter): def find_habitat(self, c: Cat) -> Forest: ...
原因在于CatResearchCenter.find_habitat的参数类型Cat需要是Animal的超类型才符合子类型规则,mypy会直接报错:
error: Argument 1 of "find_habitat" is incompatible with supertype "AnimalResearchCenter";
supertype defines the argument type as "Animal" [override]
note: This violates the Liskov substitution principle
这种情况下我们一般会用泛型来解决:
from typing import Generic, TypeVar T = TypeVar("T", bound=Animal) class AnimalResearchCenter(Generic[T]): def find_habitat(self, a: T) -> Habitat: ... class CatResearchCenter(AnimalResearchCenter[Cat]): def find_habitat(self, c: Cat) -> Forest: ...
所以我的问题是:在什么场景下,我们会希望基类中存在find_habitat(self, a: Animal) -> Habitat这样的方法?
内容的提问来源于stack exchange,提问作者Ziyuan
相关产品推荐
相关产品推荐

