我注意到mypy在进入lambda的范围时忘记了类型信息。下面是一个很小的例子来解释:
from typing import Optional, Callable
def wrapper(x: Callable[[], None]):
x()
def foo(a: int):
print(str(a))
a: Optional[int] = 0
if a is None:
exit()
wrapper(lambda: foo(a))Mypy抱怨这个代码片段有错误:Argument 1 to "foo" has incompatible type "None"; expected "int"。但是,我们之前已经检查过了a不是None。这令人惊讶地奇怪,因为如果我们直接调用foo(a) (没有包装器),它就能工作。我使用python3.6.10和mypy 0.740。
这是故意的行为吗?如果是这样的话,你将如何正确地打字呢?
谢谢!
发布于 2020-10-30 15:04:34
这不是因为lambda,而是因为a是一个闭包。简而言之,这个函数在技术上是错误的,即使特定的代码不能触发错误的路径。
与在函数中修复闭包类似的问题一样,强制按定义计算名称提供了有效的输入:
wrapper(lambda a=a: foo(a))注意,mypy cannot properly infer lambda types,所以像这样使用lambda仍然会导致错误Cannot infer type of lambda。
考虑完全等效的命名函数:
def l() -> None:
# reveal_type(a) -> Union[builtins.int, None]
return foo(a)注意a: Optional[int]在这里是如何可见的,而不是在a is None保护之后减少的a: int。因此,问题不是来自lambda,而是来自def。
问题的根源在于l和lambda都关闭了a的所有值。尽管a: None在定义l/lambda之前已经被拒绝,但是稍后重置a仍然是有效的。
a: Optional[int]
if a is None: exit()
def l() -> None:
# reveal_type(a) -> Union[builtins.int, None]
return foo(a)
a = Nonehttps://stackoverflow.com/questions/64610100
复制相似问题