使用MyPy检查简单Union类型时出现类型不兼容错误
MyPy类型检查失败原因及解决办法
这不是MyPy的bug,而是由字典类型的不变性和Union类型的匹配规则共同导致的,具体细节如下:
字典类型的不变性:Python的
Dict是可变容器,在类型系统中属于不变类型。也就是说,哪怕V1是V2的子类型,Dict[K, V1]也不能被当作Dict[K, V2]使用。你的A类型是Dict[str, Union[str, Dict[str, str]]],而{"x": {"y": "z"}}的推断类型是Dict[str, Dict[str, str]],两者的值类型(一个是Union,一个是单一字典类型)不相等,所以严格意义上不兼容。直接标注A时的特殊处理:当你把这个字典直接赋值给标注为
A的变量时,MyPy会对字典字面量做隐式类型拓宽——它会自动将字面量的类型调整为A,因为每个值都符合Union[str, Dict[str, str]]的要求。这是MyPy为了提升易用性做的特殊优化。Union类型的严格匹配:当目标类型是
Union[A, Dict[str, str]]时,MyPy会严格检查表达式类型是否兼容Union中的任意一个成员。此时表达式的类型Dict[str, Dict[str, str]]既不严格兼容A(受限于Dict的不变性),也不兼容Dict[str, str],因此触发报错。
解决办法
方法一:显式类型转换
通过cast告诉MyPy该字典的实际类型,或者用# type: ignore跳过检查:
from typing import Dict, Union, cast A = Dict[str, Union[str, Dict[str, str]]] B = Union[A, Dict[str, str]] # 使用cast明确类型 example: B = cast(A, {"x": {"y": "z"}}) # 跳过检查(不推荐,仅在确认类型安全时使用) example: B = {"x": {"y": "z"}} # type: ignore
方法二:改用协变的Mapping类型
如果不需要修改这个字典,可以用Mapping替代Dict。Mapping是协变类型,允许值类型的子类型兼容:
from typing import Mapping, Union A = Mapping[str, Union[str, Mapping[str, str]]] B = Union[A, Mapping[str, str]] example: B = {"x": {"y": "z"}} # MyPy检查通过
内容的提问来源于stack exchange,提问作者levand
相关产品推荐
相关产品推荐

