mypy中如何在泛型类参数场景正确使用泛型类型别名
解决方案
直接在模块作用域定义泛型类型别名即可,不需要把别名放进类内部,这是mypy原生支持的写法,完全兼容类场景的类型检查。
兼容所有mypy版本的通用写法
from typing import Generic, TypeVar, TYPE_CHECKING T = TypeVar("T") U = TypeVar("U") V = TypeVar("V") W = TypeVar("W") class Bar(Generic[T, U, V]): ... # 仅类型检查阶段生效,不占用运行时命名空间,不需要的话可以去掉TYPE_CHECKING判断 if TYPE_CHECKING: BarType = Bar[T, U, V] class Foo(Generic[T, U, V, W]): def do_something(self, x: BarType, y: W) -> BarType: reveal_type(x) # mypy正确推导为Bar[T, U, V] return x
这个写法下mypy会自动识别BarType是绑定了T/U/V三个TypeVar的泛型别名,在Foo类内部引用时,会自动匹配类上声明的同实例TypeVar,不需要重复书写Bar[T, U, V]长串参数,同时会自动做类型一致性校验:如果传入的Bar实例泛型参数和当前Foo实例的T/U/V不匹配,会直接报类型错误。
Python 3.12+ 新版语法写法
如果用Python 3.12及以上版本的内置泛型语法,可以用type关键字声明泛型别名,写法更简洁:
from typing import Generic class Bar[T, U, V]: ... type BarType[T, U, V] = Bar[T, U, V] class Foo[T, U, V, W]: def do_something(self, x: BarType[T, U, V], y: W) -> BarType[T, U, V]: reveal_type(x) # 正确推导为Bar[T, U, V] return x
之前两种方案失效的原因
- 类内用
ClassVar[TypeAlias]定义别名的方案从类型逻辑上就行不通:mypy只会把模块级的无特殊标记的赋值识别为类型别名,类内部的赋值会被判定为类属性。而ClassVar是所有类实例共享的属性,不可能绑定每个实例独立的泛型参数,自然会被推导为Any。 - 额外新增绑定Bar的TypeVar的方案属于冗余设计:本质是把类型别名的功能强行用泛型参数实现,自然会带来泛型参数列表冗余、实例化时需要重复传参、参数一致性无法自动校验的问题,没有实用价值。
内容的提问来源于stack exchange,提问作者Sargera
相关产品推荐
相关产品推荐

