如何解决如何为Optional [int]注释包装器?难度:当它是一个参数时
我似乎找不到一个可接受的注释,该注释的接收值是:a)函数返回int
或b)None
。麻烦的是,该函数返回的值是父函数的可选关键字参数,因此先前已声明为Optional[int]
。但是,运行时分配保证该函数永远不会返回 None
。
如果我删除了注释,则mypy
接受它为黄金。但是我更喜欢使用一些(可接受的)注释。一分钱,一英镑...
我的代码:
from typing import Optional,Callable
def myfun(p1: Optional[int] = None):
# mypy complains about this
dyn_p1:Optional[Callable[[],int]] = (lambda: p1) if p1 else None
# ... but has no problem with this
# dyn_p1 = (lambda: p1) if p1 else None
otherFun(dyn_p1)
# I expect the parameter annotation here to be checked at the point of invocation above.
def otherFun(dyn_p1: Optional[Callable[[],int]]):
pass
这是mypy
错误:
PS $ mypy .\prompt_toolkit\shortcuts\test1.py
prompt_toolkit\shortcuts\test1.py:6: error: Incompatible types in assignment (expression has type "Optional[Callable[[],Optional[int]]]",variable has type "Optional[Callable[[],int]]")
prompt_toolkit\shortcuts\test1.py:6: error: Incompatible return value type (got "Optional[int]",expected "int")
Found 2 errors in 1 file (checked 1 source file)
# comment out the first dyn_p1 and uncomment the second,run again:
PS $ mypy .\prompt_toolkit\shortcuts\test1.py
Success: no issues found in 1 source file
解决方法
只需更改以下内容
from typing import Optional,Callable
def myfun(p1: Optional[int] = None):
dyn_p1: Optional[Callable[[],Optional[int]]] = (lambda: p1) if p1 else None
otherFun(dyn_p1)
def otherFun(dyn_p1: Optional[Callable[[],Optional[int]]]):
pass
这是因为您已将p1明确定义为可选int,因此,如果lambda返回p1,则dyn_p1必须能够返回可选int,而不仅仅是int。
现在运行mypy
(venv) ➜ pythonProject mypy okay.py
Success: no issues found in 1 source file
,
我(有点)不认为这里的问题是您的lambda。我认为它实际上是p1
。
假设您改为
def myfun(p1: int = 5):
dyn_p1:Optional[Callable[[],int]] = (lambda: p1) if p1 > 0 else None
毕竟,lambda返回p1
。 p1
是一个整数。 lambda返回一个整数。 Lambda是Callable[[],int]
。除非它为None,否则Optional使一切都变得愉快。
对于您来说,p1
不是int
。这是Optional[int]
。因此MyPy正确地推断出它是Callable[[],Optional[int]]
。那与类型提示不同,所以它发出嘶哑的声音。
现在您可能会说:“但是MyPy应该能够进行代码流分析,并且知道只有在p1
不为空的情况下,lambda才会被赋值。”
哪个...是真的。 MyPy可以进行一些代码流分析。例如,可以这样:
def test(p1: Optional[int]) -> None:
p2: Union[int,str] = p1 if p1 is not None else "Fail"
我怀疑这里的收获是 lambda绑定晚了。也就是说,尽管您在分配p1
时未检查到None
,但创建{{之后,仍然将其合法地设置回None
1}}。
如果您有代码
dyn_p1
即使def myfun(p1: Optional[int] = None):
dyn_p1:Optional[Callable[[],int]] = (lambda: p1) if p1 else None
p1 = None
return dyn_p1()
myfun(5)
以int开头,结果也将是p1
,因为None
就是执行lambda的时候。
MyPy不会分析控制流以确保此变量永远不会更改为合法类型。相反,它警告您易忘的Python规则意味着它可能不像乍看起来那样可预测。
您可以做的一件事就是引入另一个标注为p1
的变量。因为将新变量更改为int
是不合法的,所以MyPy可以继续担心。
None
具有讽刺意味的是,在您的示例中,如果不进行检查,MyPy不会发现后期绑定问题。它没有将其标记为def myfun(p1: Optional[int] = None):
if p1 is not None:
p1_: int = p1
dyn_p1:Optional[Callable[[],int]] = (lambda: p1_)
else:
dyn_p1 = None
otherFun(dyn_p1)
或其他任何东西;它实际上可以推断出您想告诉它的类型!
Any
此类型检查正常。两次都显示为“ Union [def()-> builtins.int,None]”(这是Optional [Callable [[],int]]的MyPy拼写)。但是,如果您实际调用它,它会通过未经授权的def test(p1: Optional[int] = 5) -> int:
dyn_p1 = (lambda: p1) if p1 else None
reveal_type(dyn_p1)
p1 = None
reveal_type(dyn_p1)
return dyn_p1() if dyn_p1 is not None else 0
潜行。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。