Python Mypy无法从联合返回类型推断类型

时间:2018-07-12 10:41:22

标签: python mypy static-typing

这是示例代码

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也无法推断出这一点。

2 个答案:

答案 0 :(得分:5)

  

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

Mypy是正确的。您的代码中有一个错误,而mypy正确地对其进行了标记。您的代码中不能保证data['start']data['end']始终都是整数。

您的data签名是Dict[str, Union[str, int]],因此值的类型为Union[str, int]。 Mypy 必须假定传递{'start': '2018-07-12', 'end': -42}总是正确的,因此返回值必须Tuple[Union[str, int], Union[str, int]]。您声称函数返回Tuple[int, int]与此冲突。

在运行时实际上发生什么都没关系。那不是重点; mypy是静态类型检查器,旨在帮助保持运行时行为无错误。在这里重要的是,根据类型提示,可能传递startend的非整数值,因此类型检查器无法保护您可能是由于您代码中将来的错误而无意中为这两个键中的任何一个设置了字符串值。

如果要在字典中传递结构化数据,则始终必须为此而努力,因为字典实际上是错误的结构。您真的想在这里使用命名元组或a dataclass

我在这里使用的名称是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

答案 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])是工作的结果