如何定义类型让MyPy识别data_one/data_two为对应Data类实例?
让MyPy正确识别Builder返回的具体Data类型
问题背景
在Python 3.10.6 + MyPy 1.3.0的--strict模式下,原代码中my_fce返回的data_one和data_two被MyPy识别为Any类型,无法正确推断出它们是DataOne和DataTwo的实例,同时会抛出类型推导相关错误。
问题根源
原代码额外定义了类型变量R并绑定BuildInterface[T],破坏了Builder与对应Data类型的关联逻辑,导致MyPy无法推导T的具体类型。
修改方案
- 移除多余的类型变量
R,直接在my_fce中使用BuildInterface[T]作为参数类型,让MyPy能从Builder的to_data方法返回值直接推导T的具体类型 - 保留
T类型变量的bound=DataInterface约束,确保传入的Data类型符合协议要求 - 无需显式让
DataOne/DataTwo继承DataInterface,Protocol会自动适配拥有对应属性的类
修改后的完整代码
from typing import TypeVar, Protocol import dataclasses # Interfaces # class DataInterface(Protocol): @property def value(self) -> int: ... @property def name(self) -> str: ... T = TypeVar("T", bound=DataInterface, covariant=True) class BuildInterface(Protocol[T]): @property def value(self) -> int: ... def to_data(self) -> T: ... # Function # def my_fce(builder: BuildInterface[T]) -> T: return builder.to_data() # Implementation - One # @dataclasses.dataclass(frozen=True, eq=True) class DataOne: value: int name: str cfg: str @dataclasses.dataclass(frozen=True, eq=True) class BuilderOne: value: int def to_data(self) -> DataOne: return DataOne(self.value + 1, "foo", "my_cfg") builder_one = BuilderOne(1) data_one = my_fce(builder_one) reveal_type(data_one) # 现在会显示:Revealed type is "__main__.DataOne" # Implementation - Two # @dataclasses.dataclass(frozen=True, eq=True) class DataTwo: value: int name: str num: int @dataclasses.dataclass(frozen=True, eq=True) class BuilderTwo: value: int def to_data(self) -> DataTwo: return DataTwo(self.value + 1, "foo", 1) builder_two = BuilderTwo(1) data_two = my_fce(builder_two) reveal_type(data_two) # 现在会显示:Revealed type is "__main__.DataTwo"
验证结果
修改后,MyPy在--strict模式下会正确推断:
data_one的类型为DataOnedata_two的类型为DataTwo
同时不再抛出原有的类型推导错误。
内容的提问来源于stack exchange,提问作者Dolajo
相关产品推荐
相关产品推荐

