为什么mypy拒绝我的“混合工会"?类型声明? [英] Why does mypy reject my "mixed union" type declaration?

查看:29
本文介绍了为什么mypy拒绝我的“混合工会"?类型声明?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

解决 Python 聊天中的一个半相关问题时,我在 mypy 中发现了一些行为我不明白.

While troubleshooting a semi-related problem in the Python chat, I came upon some behavior in mypy that I don't understand.

from typing import Union, List, Dict

def f(x: Union[
            Dict[str, float],
            Dict[str, str],
            Dict[str, int],
    ]):
        pass

f({"a": 1})     #passes
f({"a": "b"})   #passes
f({"a": 1.0})   #passes

def g(x: Union[
            Dict[str, float],
            Dict[str, Union[str, int]],
    ]):
        pass

g({"a": 1})     #fails
g({"a": "b"})   #fails
g({"a": 1.0})   #passes

def h(x: Dict[str, Union[float, str, int]]):
    pass

h({"a": 1})     #passes
h({"a": "b"})   #passes
h({"a": 1.0})   #passes

当我在这个脚本上执行 mypy 时,它只抱怨中间函数,g:

When I execute mypy on this script, it only complains about the middle function, g:

C:\Users\Kevin\Desktop>mypy test.py
test.py:20: error: Argument 1 to "g" has incompatible type "Dict[str, int]"; expected "Union[Dict[str, float], Dict[str, Union[str, int]]]"
test.py:20: note: "Dict" is invariant -- see http://mypy.readthedocs.io/en/latest/common_issues.html#variance
test.py:20: note: Consider using "Mapping" instead, which is covariant in the value type
test.py:21: error: Argument 1 to "g" has incompatible type "Dict[str, str]"; expected "Union[Dict[str, float], Dict[str, Union[str, int]]]"
test.py:21: note: "Dict" is invariant -- see http://mypy.readthedocs.io/en/latest/common_issues.html#variance
test.py:21: note: Consider using "Mapping" instead, which is covariant in the value type
Found 2 errors in 1 file (checked 1 source file)

(正如注释所暗示的,将 Dict 替换为 Mapping 可以消除错误,但为了这个问题,我必须使用 Dict.)

(As the notes imply, replacing Dict with Mapping removes the errors, but let's say for the sake of the question that I must use Dict.)

这些错误令我感到惊讶.据我所知,每个函数的类型注释应该简化为同一组类型:一个字典,其键是字符串,值是浮点数/字符串/整数.那么为什么只有 g 有不兼容的类型?mypy 是不是被两个 Unions 的存在弄糊涂了?

These errors are surprising to me. As far as I can tell, the type annotations for each function should simplify down to the same group of types: a dict whose keys are strings, and whose values are floats/strings/ints. So why does only g have incompatible types? Is mypy somehow confused by the presence of two Unions?

推荐答案

这是因为 Dict 是不变的.它应该是不变的,因为它是可变的.

This is because Dict is invariant. It should be invariant because it is mutable.

Dict[str, int] 不是 Dict[str, Union[str, int]] 的子类型(即使 intUnion[int, str])

Dict[str, int] is not a subtype of Dict[str, Union[str, int]] (even though int is a subtype of Union[int, str])

如果你要做这样的事情怎么办:

What if you are going to do something like this:

d: Dict[str, Union[str, int]]
u: Dict[str, int]
d = u  # Mypy error: Incompatible type
d["Key"] = "value"


Mypy 假设字典是同质的:它们永远只包含一种类型.与此相反,例如,Tuples 旨在包含异构数据:允许每个项目具有不同的类型.


Mypy assumes that dictionaries are homogeneous: they will only ever contain one kind of type. In contrast to this, for example, Tuples are meant to contain heterogeneous data: each item is allowed to have a different type.

如果您需要异构Dict,您可以使用TypedDict,但只需要一组固定的字符串键:

If you need heterogenous Dict, you could use TypedDict, but only a fixed set of string keys is expected:

from typing import List, TypedDict

Mytype = TypedDict('Mytype', {'x': str, 'a': List[str]})
s: Mytype = {"x": "y", "a": ["b"]}

s['a'].append('c')

注意:

除非您使用 Python 3.8 或更新版本(其中 TypedDict 在标准库输入模块中可用),否则您需要使用 pip 安装 Typing_extensions 以使用 TypedDict

Unless you are on Python 3.8 or newer (where TypedDict is available in standard library typing module) you need to install typing_extensions using pip to use TypedDict

这篇关于为什么mypy拒绝我的“混合工会"?类型声明?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆