You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为基于实例属性的判别式联合类型(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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.14 17:59:35