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

Python3.9下用Union声明类型时mypy报不兼容错误

解决Python3.9下Mypy枚举字典类型不兼容问题

原始代码

from enum import Enum
from typing import Dict, Union, Type

class MyEnum(Enum):
    FIRST = 1, 'first'
    SECOND = 2 , 'second'

__myenum_int_ref: Dict[int, MyEnum] = {k.value[0]: k for k in MyEnum}
__myenum_str_ref: Dict[str, MyEnum] = {k.value[1]: k for k in MyEnum}
__myenum_str_ref.update({k.name: k for k in MyEnum})

__flags_ref: Dict[Union[Type[str], Type[int]], Dict[Union[str, int], MyEnum]] = {
    str: __myenum_str_ref,
    int: __myenum_int_ref,
}

Mypy报错信息

function.py:14: error: Dict entry 0 has incompatible type "Type[str]": "Dict[str, MyEnum]"; expected "Union[Type[str], Type[int]]": "Dict[Union[str, int], MyEnum]"
function.py:15: error: Dict entry 1 has incompatible type "Type[int]": "Dict[int, MyEnum]"; expected "Union[Type[str], Type[int]]": "Dict[Union[str, int], MyEnum]"

问题原因

Mypy对字典类型的协变检查严格:Dict[str, MyEnum]并非Dict[Union[str, int], MyEnum]的子类型——前者键只能是str,后者允许str或int,类型约束不匹配。即便你明确知道str键对应的值只会接收str键的字典,Mypy默认也不会做上下文推断。

解决方案

方案1:用TypedDict精确映射结构(最优解)

通过TypedDict明确指定每个键对应的字典类型,类型最严谨:

from enum import Enum
from typing import Dict, Type, TypedDict

class MyEnum(Enum):
    FIRST = 1, 'first'
    SECOND = 2 , 'second'

__myenum_int_ref: Dict[int, MyEnum] = {k.value[0]: k for k in MyEnum}
__myenum_str_ref: Dict[str, MyEnum] = {k.value[1]: k for k in MyEnum}
__myenum_str_ref.update({k.name: k for k in MyEnum})

class FlagsRef(TypedDict):
    str: Dict[str, MyEnum]
    int: Dict[int, MyEnum]

__flags_ref: FlagsRef = {
    str: __myenum_str_ref,
    int: __myenum_int_ref,
}

方案2:用cast做类型断言

不修改原有结构,手动告诉Mypy类型匹配:

from enum import Enum
from typing import Dict, Union, Type, cast

class MyEnum(Enum):
    FIRST = 1, 'first'
    SECOND = 2 , 'second'

__myenum_int_ref: Dict[int, MyEnum] = {k.value[0]: k for k in MyEnum}
__myenum_str_ref: Dict[str, MyEnum] = {k.value[1]: k for k in MyEnum}
__myenum_str_ref.update({k.name: k for k in MyEnum})

__flags_ref: Dict[Union[Type[str], Type[int]], Dict[Union[str, int], MyEnum]] = {
    str: cast(Dict[Union[str, int], MyEnum], __myenum_str_ref),
    int: cast(Dict[Union[str, int], MyEnum], __myenum_int_ref),
}

方案3:调整子字典类型注解

直接将子字典声明为Dict[Union[str, int], MyEnum],牺牲子字典的类型精确性换兼容性:

from enum import Enum
from typing import Dict, Union, Type

class MyEnum(Enum):
    FIRST = 1, 'first'
    SECOND = 2 , 'second'

__myenum_int_ref: Dict[Union[str, int], MyEnum] = {k.value[0]: k for k in MyEnum}
__myenum_str_ref: Dict[Union[str, int], MyEnum] = {k.value[1]: k for k in MyEnum}
__myenum_str_ref.update({k.name: k for k in MyEnum})

__flags_ref: Dict[Union[Type[str], Type[int]], Dict[Union[str, int], MyEnum]] = {
    str: __myenum_str_ref,
    int: __myenum_int_ref,
}

内容的提问来源于stack exchange,提问作者Lucas Coppio

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 15:15:42