为什么Mypy拒绝我的“混合工会"?类型声明? [英] Why does mypy reject my "mixed union" type declaration?
问题描述
对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)
(正如注释所暗示的那样,用Mapping
替换Dict
可以消除错误,但是为了回答这个问题,我必须使用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是否因两个联合的存在而感到困惑?
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
是不变的.
Dict[str, int]
不是Dict[str, Union[str, int]]
的子类型(即使int
是Union[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’].upper()
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来安装type_Ditensions才能使用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屋!