Mypy能否推断方法返回实例为子类类型?
解决Mypy中父类方法返回子类实例的类型推断问题
原代码如下:
class A: def __init__(self) -> None: pass def copy(self) -> "A": return self.construct_self() def construct_self(self) -> "A": return A() class B(A): def __init__(self) -> None: super().__init__() def copy(self) -> "B": return super().copy() def construct_self(self) -> "B": return B()
运行Mypy时会触发错误:error: Incompatible return value type (got "A", expected "B") [return-value],但实际运行B().copy()会正确返回B实例。要让Mypy正确推断父类方法返回子类类型,可通过泛型约束实现:
修改后的代码
from typing import TypeVar # 定义绑定到A的类型变量,限制T为A或其子类 T = TypeVar('T', bound='A') class A: def __init__(self) -> None: pass # 用self: T标注,让Mypy根据实例实际类型推断返回值类型 def copy(self: T) -> T: return self.construct_self() def construct_self(self: T) -> T: return self.__class__() # 用self.__class__创建实例更灵活,也可保留原return A() class B(A): def __init__(self) -> None: super().__init__() def construct_self(self) -> "B": return B()
说明
- 泛型约束:通过
TypeVar定义与A绑定的类型变量T,在父类方法中用self: T标注self的类型,Mypy会根据当前实例的实际类型(比如B的实例)自动推断T为对应子类类型,因此copy方法的返回类型会被识别为T(即B)。 - 无需重写copy方法:修改后子类
B不需要重写copy,父类的泛型逻辑已经能让Mypy正确识别B().copy()返回B实例;如果确实需要重写copy,直接标注返回类型为B即可,此时super().copy()的返回类型会被正确推断为B,不会触发类型错误。 - 灵活构造实例:将
construct_self中的return A()改为return self.__class__(),可以让父类自动创建当前子类的实例,子类只需重写construct_self实现自定义构造逻辑即可。
这样修改后,Mypy能正确识别B().copy()的返回类型为B,调用B的专属方法不会触发类型错误,同时符合你将任务分发到子类实现的场景需求。
内容的提问来源于stack exchange,提问作者GentleMin
相关产品推荐
相关产品推荐

