为何给TypeVar添加bound会导致mypy无法识别该Protocol?
带绑定TypeVar导致Protocol类型检查失败的原因分析
问题场景
以下代码中,func()内的x: Foo[V] = Bar[V]()赋值无法通过类型检查,但如果移除K的bound=int限制,赋值就能正常通过:
from typing import Generic, Protocol, TypeVar T = TypeVar("T") V = TypeVar("V") K = TypeVar("K", bound=int) # 带绑定的TypeVar class Gen(Generic[T, K]): ... class Foo(Protocol[T]): def g(self, t: Gen[T, K]) -> T: ... class Bar(Generic[T]): def g(self, t: Gen[T, K]) -> T: raise RuntimeError def func(v: V) -> None: x: Foo[V] = Bar[V]() # 此处类型检查失败
核心原因
本质是Protocol的子类型检查规则和带绑定TypeVar的作用范围共同导致的:
- 当
K带bound=int时,Foo[T]这个Protocol对g方法的要求是:它必须能接受任意满足K <= int的Gen[T, K]实例(也就是所有int子类对应的Gen对象)。 - 而
Bar[T]的g方法虽然签名看起来一致,但Bar并没有把K作为自己的泛型参数。类型检查器会认为,Bar[T].g只能接受某个特定的K(符合int绑定的具体类型),而非所有符合约束的K。 - Protocol要求实现类的方法参数类型必须满足逆变兼容:实现类的参数类型要能覆盖Protocol参数类型能接受的所有值。显然
Bar[T].g做不到这一点,因此类型检查不通过。
当移除bound=int限制后,K变成无约束的TypeVar,此时Gen[T, K]可以匹配任何类型。Bar[T].g的参数类型和Foo[T].g的参数类型完全兼容,类型检查器会认为两者签名一致,因此赋值通过。
内容的提问来源于stack exchange,提问作者leontrolski
相关产品推荐
相关产品推荐

