子类用父类属性子类型重写时如何解决mypy类型不兼容问题
解决Mypy中列表子类类型兼容性问题
问题代码
class B: pass class InheritsB1(B): pass class InheritsB2(B): pass class A: prop: list[B] class InheritsA1(A): prop: list[InheritsB1] class InheritsA2(A): prop: list[InheritsB2]
问题描述
运行上述代码时,mypy会抛出错误:
Incompatible types in assignment (expression has type "List[InheritsB2]", base class "A" defined the type as "List[B]")
虽然InheritsB1、InheritsB2都是B的子类,但Python的list是不变类型——list[InheritsB1]并不被视为list[B]的子类,因此mypy会判定类型不兼容。我们需要让父类A的prop支持“B或其任意单一子类的列表”,且列表内不会混合不同子类实例。
解决方案
使用泛型(Generic)+ 绑定类型变量(Bound TypeVar)来实现类型兼容,具体修改如下:
from typing import TypeVar, Generic # 定义一个类型变量,只能绑定B或其子类 T = TypeVar('T', bound=B) class B: pass class InheritsB1(B): pass class InheritsB2(B): pass # 让A继承Generic[T],成为泛型类 class A(Generic[T]): prop: list[T] # 子类继承时指定具体的类型参数 class InheritsA1(A[InheritsB1]): pass class InheritsA2(A[InheritsB2]): pass
方案说明
- 通过
TypeVar('T', bound=B)限制类型变量T只能是B或其子类,保证类型安全。 - 父类
A声明为泛型类后,prop的类型list[T]会随子类指定的T而变化:InheritsA1的prop自动变为list[InheritsB1],InheritsA2的prop自动变为list[InheritsB2]。 - 这种方式既满足了“列表仅包含单一子类实例”的需求,又让mypy能够正确识别类型兼容性,同时新增
B的子类时无需修改父类代码,扩展性更强。
替代方案(不推荐)
如果不想使用泛型,有两种妥协方式,但都存在明显缺陷:
- 在子类的
prop声明后添加# type: ignore忽略mypy错误,但会牺牲类型检查的严谨性。 - 将父类
A的prop声明为list[B | InheritsB1 | InheritsB2],但新增B的子类时需要手动更新联合类型,灵活性极差。
内容的提问来源于stack exchange,提问作者Some Guy
相关产品推荐
相关产品推荐

