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

如何用mypy静态检查字典包含Union类型所有选项的键?

如何用mypy静态检查字典键是否覆盖Union类型的所有选项?

我定义了由多个dataclass组成的Union类型PossibleOption,想要创建以这些类的实例为键的字典,需要用mypy静态检查该字典是否包含Union中每个选项对应的键。现有代码如下:

from dataclasses import dataclass
from typing import Union

@dataclass
class Option1:
    def __hash__(self):   # 不用太关注这个方法,字典需要可哈希的键,仅此而已
        return hash(type(self))

@dataclass
class Option2:
    def __hash__(self):
        return hash(type(self))

@dataclass
class Option3:
    def __hash__(self):
        return hash(type(self))

PossibleOption = Union[Option1, Option2, Option3]

# 我想要创建这样的字典:
a = {Option1(): "a", Option2(): "bb", Option3(): "cc"}
# 比如 print(a[Option2()]) 会输出 "bb"

我知道可以通过定义接收PossibleOption为参数的函数,使用match语句返回对应值,mypy能检查是否覆盖所有选项:

def equivalent_to_dictionary(po: PossibleOption) -> str:
    match po:
        case Option1():
            return "aa"
        case Option2():
            return "bb"
        case Option3():
            return "cc"

但我希望保持用户使用方式更简洁,请问是否有办法用mypy静态检查字典的键是否包含Union类型的每个选项?


可行的解决方案

方法1:构建函数+match语句强制覆盖

编写一个专门的字典构建函数,利用mypy对match语句的覆盖检查特性,间接保证字典包含所有必要键。如果Union类型新增了选项,mypy会在match处提示未覆盖的case,从而避免遗漏键:

from dataclasses import dataclass
from typing import Union, Dict

@dataclass
class Option1:
    def __hash__(self):
        return hash(type(self))

@dataclass
class Option2:
    def __hash__(self):
        return hash(type(self))

@dataclass
class Option3:
    def __hash__(self):
        return hash(type(self))

PossibleOption = Union[Option1, Option2, Option3]

def build_option_dict() -> Dict[PossibleOption, str]:
    option_dict: Dict[PossibleOption, str] = {}
    # 遍历所有Option类,创建实例并添加到字典
    for option_cls in [Option1, Option2, Option3]:
        instance = option_cls()
        match instance:
            case Option1():
                option_dict[instance] = "a"
            case Option2():
                option_dict[instance] = "bb"
            case Option3():
                option_dict[instance] = "cc"
    return option_dict

# 使用时直接调用函数获取字典
a = build_option_dict()

方法2:TypedDict+类型推导转换

由于你的Option实例哈希仅依赖类型,可先通过TypedDict强制类类型的键完整,再转换成实例为键的字典,兼顾类型检查和使用简洁性:

from dataclasses import dataclass
from typing import Union, Literal, TypedDict

@dataclass
class Option1:
    def __hash__(self):
        return hash(type(self))

@dataclass
class Option2:
    def __hash__(self):
        return hash(type(self))

@dataclass
class Option3:
    def __hash__(self):
        return hash(type(self))

# 定义类类型的Literal
OptionType = Literal[Option1, Option2, Option3]
# 定义total=True的TypedDict,强制包含所有类类型的键
class OptionTypeDict(TypedDict, total=True):
    Option1: str
    Option2: str
    Option3: str

# 先构建符合类型约束的类-值映射
type_map: OptionTypeDict = {
    Option1: "a",
    Option2: "bb",
    Option3: "cc"
}

# 转换成实例为键的目标字典
a = {cls(): val for cls, val in type_map.items()}

这种方式下,若遗漏某个类的键,mypy会直接报错,同时最终的字典使用方式和你原本的需求完全一致。

方法3:自定义mypy插件(进阶)

如果上述方法仍不符合需求,可编写自定义mypy插件,实现对字典键是否覆盖Union所有选项的直接检查。不过该方案需要编写插件代码,学习成本较高,适合复杂场景。


内容的提问来源于stack exchange,提问作者Pierre-olivier Gendraud

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 23:23:15