Mypy:在映射类型中使用联合不能按预期工作

cha*_*gne 6 python mypy

考虑以下代码:

def foo(a: dict[str | tuple[str, str], str]) -> None:
    pass


def bar(b: dict[str, str]) -> None:
    foo(b)


def baz(b: dict[tuple[str, str], str]) -> None:
    foo(b)


foo({"foo": "bar"})
foo({("foo", "bar"): "bar"})
Run Code Online (Sandbox Code Playgroud)

当在严格模式下使用 mypy 检查时,会产生以下错误:

file.py:6: error: Argument 1 to "foo" has incompatible type "Dict[str, str]"; expected "Dict[Union[str, Tuple[str, str]], str]"
file.py:9: error: Argument 1 to "foo" has incompatible type "Dict[Tuple[str, str], str]"; expected "Dict[Union[str, Tuple[str, str]], str]"
Run Code Online (Sandbox Code Playgroud)

这对我来说似乎没有意义。该参数被定义为接受dict以字符串或元组作为键,以字符串作为值的 a。然而,当明确注释时,这两种变体都不被接受。然而,当将这样的字典直接传递给函数时,它们确实可以工作。在我看来,mypy 期望一个字典必须能够将联合体的两个选项作为键。我不明白为什么?如果键的约束是字符串或字符串的元组,则传递任何一个都可以。正确的?我在这里错过了什么吗?

use*_*ica 4

Adict[str | tuple[str, str], str]不仅仅是带有strtuple[str, str]键的字典。这是一个你可以添加更多 str或键的字典tuple[str, str]

您无法将str键添加到 a dict[tuple[str, str], str],也无法将tuple[str, str]键添加到 a dict[str, str],因此这些类型不兼容。

如果将文字字典直接传递给foo(or to baror baz),则该文字没有静态类型。mypy 根据上下文推断字典的类型。可以根据文本的上下文推断出许多不同的类型。当您传递bfooinsidebar或时baz,已经有一个静态类型,并且该类型与的签名b不兼容。foo