Python带受限TypeVar的泛型类继承时mypy报错问题咨询
问题成因
这是mypy 0.910及更早版本的已知泛型推断缺陷:当泛型父类使用受限TypeVar(带明确类型约束/绑定的TypeVar)时,子类透传泛型参数给父类的场景下,mypy无法正确将子类的泛型参数和父类的受限TypeVar做关联,会错误地将二者判定为不兼容的独立类型,因此在super().__init__(v)调用时报类型不匹配错误。
你观察到的两个现象都和这个缺陷直接相关:
reveal_type输出正常,是因为这个缺陷仅出现在类定义阶段的泛型关联逻辑,实例化时mypy可以通过传入的具体参数值正确推断实例的实际类型- 受限TypeVar场景下必须给
self.v加类型注解,是因为泛型关联断裂后,mypy无法从父类__init__的入参类型自动推断self.v的类型,无界TypeVar的推断逻辑更简单,不会触发这个问题。
你业务中使用Callable[[Any], T]的场景触发的是完全相同的缺陷,和TypeVar的具体约束类型无关。
解决方案
方案1:升级mypy版本(推荐)
这个泛型推断缺陷已经在mypy 0.940及之后的稳定版本修复,直接升级mypy即可解决问题,不需要修改任何业务代码:
pip install --upgrade mypy
方案2:兼容旧版mypy的代码修改
如果必须保留mypy 0.910版本,可以通过两种代码修改方式规避问题:
方式A:显式声明子类继承Generic
手动声明子类自身继承Generic,强制mypy关联父子类的泛型参数:
from typing import TypeVar, Generic T = TypeVar("T", str, int) class Base(Generic[T]): def __init__(self, v: T): self.v = v # 无需额外注解即可被正确推断 @property def value(self) -> T: return self.v # 显式继承Generic[T],强制关联泛型参数 class Child(Generic[T], Base[T]): def __init__(self, v: T): super().__init__(v) x = Child(123) reveal_type(x.value)
方式B:添加临时类型断言
如果不想修改类的继承结构,也可以在调用父类构造方法时添加类型断言:
from typing import TypeVar, Generic, cast T = TypeVar("T", str, int) class Base(Generic[T]): def __init__(self, v: T): self.v: T = v @property def value(self) -> T: return self.v class Child(Base[T]): def __init__(self, v: T): super().__init__(cast(T, v)) # 断言参数类型匹配父类要求
内容的提问来源于stack exchange,提问作者Zulan
相关产品推荐
相关产品推荐

