我使用disallow-untyped-defs选项运行mypy。当我使用@overload注释函数类型并在定义中省略注释时,mypy仍然会产生错误。对我来说,该功能似乎应该被注释。
example.py:
from typing import overload
@overload
def f(arg: int) -> int: ...
@overload
def f(arg: str) -> str: ...
def f(arg):
if type(arg) == int:
return 1
elif type(arg) == str:
return "a"
else:
raise ValueError
命令行:
mypy --disallow-untyped-defs example.py
输出:
example.py:7: error: Function is missing a type annotation
Found 1 error in 1 file (checked 1 source file)
这是预期的行为。 Mypy希望您将类型注释添加到重载的实现中,例如:
from typing import overload, Union
@overload
def f(arg: int) -> int: ...
@overload
def f(arg: str) -> str: ...
def f(arg: Union[int, str]) -> Union[int, str]:
if type(arg) == int:
return 1
elif type(arg) == str:
return "a"
else:
raise ValueError
这样,mypy仍将具有成功键入检查f的正文所需的所有信息。
mypy不会基于重载类型签名自动推断实现类型签名,或尝试使用重载签名两次尝试对实现进行类型检查的原因是,这两个签名通常最终会彼此非常不同。
例如,这是一个更复杂的重载示例:
@overload
def zip(/, i1: Iterable[_T1]) -> Iterator[Tuple[_T1]]: ...
@overload
def zip(/, i1: Iterable[_T1], i2: Iterable[_T2]) -> Iterator[Tuple[_T1, _T2]]: ...
@overload
def zip(/, i1: Iterable[_T1], i2: Iterable[_T2],
i3: Iterable[_T3]) -> Iterator[Tuple[_T1, _T2, _T3]]: ...
@overload
def zip(/, i1: Iterable[_T1], i2: Iterable[_T2], i3: Iterable[_T3],
i4: Iterable[_T4]) -> Iterator[Tuple[_T1, _T2, _T3, _T4]]: ...
@overload
def zip(/, i1: Iterable[_T1], i2: Iterable[_T2], i3: Iterable[_T3],
i4: Iterable[_T4], i5: Iterable[_T5]) -> Iterator[Tuple[_T1, _T2, _T3, _T4, _T5]]: ...
@overload
def zip(/, i1: Iterable[Any], i2: Iterable[Any], i3: Iterable[Any],
i4: Iterable[Any], i5: Iterable[Any], i6: Iterable[Any],
*remainder: Iterable[Any]) -> Iterator[Tuple[Any, ...]]: ...
def zip(*iterables: Iterable[Any]) -> Iterator[Tuple[Any, ...]]:
sentinel = object()
iterators = [iter(it) for it in iterables]
while iterators:
result = []
for it in iterators:
elem = next(it, sentinel)
if elem is sentinel:
return
result.append(elem)
yield tuple(result)
mypy推断在这个示例中确切应该是什么实现签名非常具有挑战性:参数数量不匹配,弄清楚所有TypeVar怎么处理(保留它们?丢弃它们?)很棘手...
这些都是mypy从理论上可以解决的问题,但是从长远来看,它是否真的为用户节省了这么多时间,目前尚不清楚。在像这样的复杂情况下,用户实际上可能更希望能够说明实现签名的确切含义。
((如果问题是(a)困难而(b)是小问题,则它往往无法解决,尤其是在开源项目中。)
因此,为了保持一致的体验,mypy不会在每种情况下都尝试自动推断实现签名。