Python mypy 无法从联合 return 类型推断类型

Python mypy unable to infer type from union return types

这里是示例代码

from typing import Dict, Union, Tuple


def select_range(data: Dict[str, Union[str, int]]) -> Tuple[int, int]:
    if data['start'] and data['end']:
        return data['start'], data['end']
    return 1, 1

select_range({})

Mypy 输出:

mypy different_return.py
different_return.py:6: error: Incompatible return value type (got 
"Tuple[Union[str, int], Union[str, int]]", expected "Tuple[int, int]")

即使其中一个字典值是 int,mypy 也无法推断出它。

Even though one of the dictionary values is int, mypy is unable to infer that.

Mypy 是正确的。你的代码有一个错误,mypy 正确地标记了它。您的代码无法保证 data['start']data['end'] 始终为整数。

您的 data 签名是 Dict[str, Union[str, int]],因此值的类型是 Union[str, int]。 Mypy必须假设传入{'start': '2018-07-12', 'end': -42}总是正确的,所以return值必须Tuple[Union[str, int], Union[str, int]].您声称函数 returns Tuple[int, int] 与此冲突。

实际上在运行时发生了什么并不重要。这不是重点; mypy 是一个静态类型检查器,旨在帮助您保持运行时行为无错误。这里重要的是,根据类型提示,可能startend传递非整数值,因此类型检查器不能'不会保护您免受代码中未来错误的影响,这些错误会意外地为这两个键中的任何一个设置字符串值。

如果您在字典中传递结构化数据,您将始终不得不为此与 mypy 作斗争,因为字典确实是错误的结构。您真的想在这里使用命名元组或

我在这里使用的名称是 FooBar,但对于您的特定应用程序,我相信您传递的数据结构会有更好的名称:

from typing import NamedTuple

class FooBar(NamedTuple):
    start: int
    end: int
    # other fields, perhaps with defaults and Optionals


def select_range(data: FooBar) -> Tuple[int, int]:
    if data.start and data.end:
        return data.start, data.end
    return 1, 1

代码一切都很好。你忘了获取函数参数:

from typing import Dict, Union, Tuple


def select_range(data: Dict[str, Union[str, int]]) -> Tuple[int, int]:
    print (data)
    if data['start'] and data['end']:
        return data['start'], data['end']
    return 1, 1

print (select_range({"start":[1,5], 'end':[2,6]}))

使用它来查找一些参数:

from typing import Dict, Union, Tuple

def select_range(data: Dict[str, Union[str, int]]) -> Tuple[int, int]:
#    print (data)
    if 'start' in data and 'end' in data:
        return data['start'], data['end']
    return 1, 1

print (select_range({"start":[5], 'end':[6]}))
#select_range({})

([5], [6]) 是工作的结果