如何将工厂函数返回值的类型提示从父类缩小到子类?
解决工厂函数返回实例的类型提示问题
问题场景
你有一个外部工厂函数Printer.make(),它根据传入的字符串参数返回不同子类的实例,但类型检查器始终将变量识别为父类Blueprint,导致子类的专属方法无法被IDE正确识别:
class Printer: def make(self, blueprint:str) -> Blueprint: ... class PrintA(Blueprint): def a_specific(self) -> int: ... class PrintB(Blueprint): def b_specific(self, args): """docstring""" # 手动标注类型但IDE仍识别为Blueprint a : PrintA = Printer().make("A") b : PrintB = Printer().make("B") # 使用子类方法时无正确类型提示 result = a.a_specific() # 返回值被识别为Any b.b_specific(arg) # 方法参数、描述无提示
你无法修改Printer或Blueprint类本身,但可以修改对应的*.pyi文件,且子类数量较多,需要让IDE正确识别子类的类型提示。
解决方案
方法1:使用typing.cast强制类型转换
直接在代码中用cast告诉类型检查器信任你标注的子类类型,无需修改*.pyi文件:
from typing import cast a: PrintA = cast(PrintA, Printer().make("A")) b: PrintB = cast(PrintB, Printer().make("B"))
这样IDE会直接使用你指定的PrintA/PrintB类型进行提示,子类的专属方法、返回值类型都能被正确识别。
方法2:修改*.pyi文件添加函数重载
如果希望全局生效且避免在业务代码中重复写cast,可以在对应的*.pyi文件中给Printer.make()添加重载定义,让类型检查器根据传入的参数自动推断返回类型:
from typing import overload, Literal class Printer: @overload def make(self, blueprint: Literal["A"]) -> PrintA: ... @overload def make(self, blueprint: Literal["B"]) -> PrintB: ... # 其他子类可按此格式添加重载 def make(self, blueprint: str) -> Blueprint: ...
添加重载后,当你调用Printer().make("A")时,类型检查器会自动推断返回PrintA类型,无需手动标注变量类型,IDE也能直接识别子类的专属方法。
说明
你尝试的# type: ignore[override]并不适用,因为该注释用于忽略方法重载/覆盖的错误提示,而当前场景没有报错,只是类型推断不符合预期。上述两种方法才是针对此类场景的正确解决方案。
内容的提问来源于stack exchange,提问作者Daraan
相关产品推荐
相关产品推荐

