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

查看:96
本文介绍了为什么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)

(正如注释所暗示的那样,用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]]的子类型(即使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’].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屋!

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