修复此类函数的 mypy 的最佳方法是什么?
from typing import Union
def a(b: int) -> Union[int, str]:
if b:
return b
else:
return '2'
c: int = a(1)
d: str = a(0)
mypy 结果:
error: Incompatible types in assignment (expression has type "int | str", variable has type "int") [assignment]
error: Incompatible types in assignment (expression has type "int | str", variable has type "str") [assignment]
你遇到的 mypy 错误是因为,虽然你的函数
a
被声明为返回
int
或
str
,但是 mypy 无法在分配给
c
和
d
时提前知道它将在每次调用中返回哪种类型。
你有几个选项可以解决这个问题:
1. 类型缩小:
你可以在赋值前检查返回值的类型:
from typing import Union
def a(b: int) -> Union[int, str]:
if b:
return b
else:
return '2'
result = a(1)
if isinstance(result, int):
c: int = result
else:
c = -1 # 或者其他处理方式
result2 = a(0)
if isinstance(result2, str):
d: str = result2
else:
d = "" # 或者其他处理方式
这告诉 mypy,如果检查通过,则在
if
块中变量的类型是已知的。
2. 使用
cast
:
如果你确定函数在特定情况下会返回什么类型,你可以使用
cast
来告诉 mypy:
from typing import Union, cast
def a(b: int) -> Union[int, str]:
if b:
return b
else:
return '2'
c: int = cast(int, a(1)) # 我们知道 a(1) 返回 int
d: str = cast(str, a(0)) # 我们知道 a(0) 返回 str
但是,请谨慎使用
cast
,因为它会绕过类型检查,如果使用不当可能会导致运行时错误。
3. 更改函数设计:
理想情况下,最好让函数返回一致的类型。如果可能,考虑重构你的函数以始终返回相同类型。
这三种方法中,
类型缩小
通常是首选,因为它最安全且最明确。 使用
cast
应该作为最后的手段,并且只有在你完全确定函数行为的情况下才使用。 而
更改函数设计
是更根本的解决方案,但可能并不总是可行。