如何为基于实例属性的判别式联合类型(Discriminated union)实现精准类型提示?
如何为基于实例属性的判别式联合类型(Discriminated union)实现精准类型提示?
这个需求其实就是要实现**判别式联合类型(Discriminated Union)**的类版本,让mypy、pyright这类类型检查器能根据attr2的值自动推断attr1的具体类型,我给你两种实用的方案:
方案一:使用TypeGuard创建类型守卫方法
TypeGuard是Python typing模块里专门用来定义“类型守卫”的工具,它能帮类型检查器把判断逻辑和类型断言绑定在一起,自动识别分支里的类型。
先看完整代码示例:
from typing import Union, Literal, TypeGuard # 先定义你的基础类型(这里用空类示例,实际替换成你的真实类型) class Attr11: pass class Attr12: pass class Attr3: pass class MyClass: def __init__(self): self.attr1: Union[Attr11, Attr12] self.attr2: Literal["val1", "val2", "val3"] self.attr3: Attr3 # 定义类型守卫方法:当返回True时,告诉检查器attr1是Attr11类型 def is_val1_case(self) -> TypeGuard[Attr11]: return self.attr2 == "val1" # 使用示例 obj = MyClass() if obj.is_val1_case(): # 这里类型检查器会明确知道obj.attr1是Attr11类型 reveal_type(obj.attr1) # 输出: Attr11 else: # 自动推断obj.attr1是Attr12类型 reveal_type(obj.attr1) # 输出: Attr12
这个方案的好处是逻辑复用性强,只要调用这个守卫方法,类型检查器就能自动识别类型,不用重复写断言。
方案二:使用@overload结合泛型类标注方法
如果你的逻辑是在类的方法里处理,用@overload来定义不同分支的类型签名,配合泛型类能更精准地约束类型:
from typing import Union, Literal, overload, Generic, TypeVar # 定义类型变量,限定为Attr11或Attr12 T = TypeVar("T", Attr11, Attr12) # 先定义基础类型 class Attr11: pass class Attr12: pass class Attr3: pass class MyClass(Generic[T]): def __init__(self): self.attr1: T self.attr2: Literal["val1", "val2", "val3"] self.attr3: Attr3 # 重载方法:当attr2是"val1"时,self的泛型类型是Attr11 @overload def process(self: "MyClass[Attr11]", attr2: Literal["val1"]) -> None: ... # 重载方法:当attr2是"val2"/"val3"时,self的泛型类型是Attr12 @overload def process(self: "MyClass[Attr12]", attr2: Literal["val2", "val3"]) -> None: ... # 实际实现方法 def process(self, attr2=None): if attr2 is None: attr2 = self.attr2 if attr2 == "val1": # 这里类型检查器会识别self.attr1是Attr11 reveal_type(self.attr1) else: # 这里会识别self.attr1是Attr12 reveal_type(self.attr1)
这种方案适合在类内部处理业务逻辑时,通过重载明确不同参数分支对应的实例类型,让类型检查更严谨。
另外补充个小技巧:如果只是临时在某个分支里断言类型,也可以直接用assert isinstance(obj.attr1, Attr11),但这种方式只能在当前分支生效,复用性不如TypeGuard。
备注:内容来源于stack exchange,提问作者AnotherSherlock
相关产品推荐
相关产品推荐

