mypy中dict[str, str]无法赋值更新到dict[object, str]是设计如此吗
结论
这是mypy的有意设计,核心逻辑来自泛型的型变规则。
核心原因
Python 中可变的dict类型的键、值泛型参数都是**不变(invariant)**的,也就是说即使类型A是类型B的子类型,dict[A, Any]也不会被视为dict[B, Any]的子类型。
这个设计是为了保证类型安全:假设允许你把dict[str, str]赋值给dict[object, str],你就可以合法地往dict[object, str]类型的变量里插入整数、浮点数等非字符串类型的键,此时再通过原dict[str, str]类型的引用读取键时,就会出现类型不匹配的问题,破坏类型系统的可靠性。
不同操作的差异解释
- 手动循环赋值不会报错的原因:每次单独给
x[k] = v赋值时,mypy只会校验当前k的类型是否符合x的键类型要求,str是object的子类型,赋值单个键本身是合法操作,不存在破坏类型约束的风险。 dict()构造、update、解包合并、|=运算符报错的原因:这些方法的类型标注要求传入的映射的键类型与目标字典的键类型严格匹配,符合dict不变的型变规则,因此即使子类型也不会被放行。
可行解决方案
- 如果你只需要读取字典内容,不需要修改,可以将目标变量的类型标注为
Mapping[object, str]:Mapping是只读映射类型,它的键泛型参数是协变的,因此dict[str, str]可以直接赋值给Mapping[object, str]类型的变量。 - 如果你确实需要得到
dict[object, str]类型的可变字典,可以使用字典推导式构造新字典:y: dict[object, str] = {k: v for k, v in x.items()},mypy会自动推导匹配宽类型。 - 也可以使用
typing.cast显式强转,适合你确认操作安全、需要跳过类型校验的场景:y = cast(dict[object, str], x)。
内容的提问来源于stack exchange,提问作者Vincent
相关产品推荐
相关产品推荐

