Mypy
跳转到导航
跳转到搜索
用法
mypy --enable-error-code possibly-undefined xxx
可使用--allow-redefinition参数来允许更新变量的类型[1]。
已知问题
type: ignore 必须位于同一行
当一行太长时,如:
conf = configparser.ConfigParser(dict_type=dict, allow_no_value=True)
要忽略第一个参数的报错而不使行过长,只能写成:
conf = configparser.ConfigParser( # type: ignore
dict_type=dict, allow_no_value=True)
无法推断出联合类型
比如对于 str 和 pathlib.Path 组成的列表,推断结果为 List[object] 然后被拒绝传入 subprocess.Popen。
又如无法对 List[str]和 List[Union[str, os.PathLike]]相加:
error: Unsupported operand types for + ("List[str]" and "List[Union[str, _PathLike[Any]]]")
不支持变量名 shadowing
当变量名称被复用时,mypy 还认为是同一类型。尤其是传入可选值,然后内部处理掉 None 的情况时。使用不同的名称会占用大脑的处理空间。
不支持可选属性
当对象有可能有某个属性时,mypy 无法识别 hasattr 判断之后,该属性必然存在。
不识别 TypeError 异常处理
如下代码无法通过检查:
def t(x: Optional[str]) -> Optional[int]:
try:
return int(x)
except (ValueError, TypeError):
return None
max 函数的支持不好
如下代码能够通过检查:
def f(a: Union[int, str], b: Union[int, str]) -> Union[int, str]:
return max(a, b)
而 max(int, str) 会返回 object 类型。
不支持为类添加属性
这导致无法将子类作为父类的属性,例如下边的代码,无论是在类定义里添加类型注解,还是定义好之后再赋值,均无法通过 mypy:
class BuildResult:
def __init__(self) -> None:
if __class__ is self.__class__:
raise TypeError('use subclasses')
def __bool__(self) -> bool:
return self.__class__ in [self.successful, self.staged]
def __init_subclass__(cls):
setattr(__class__, cls.__name__, cls)
def __repr__(self) -> str:
name = self.__class__.__name__
return f'<BuildResult.{name}>'
class successful(BuildResult):
pass
class staged(BuildResult):
pass
class failed(BuildResult):
def __init__(self, exc: Exception) -> None:
self.exc = exc
def __repr__(self) -> str:
name = self.__class__.__name__
return f'<BuildResult.{name}: {self.exc!r}>'
class skipped(BuildResult):
def __init__(self, reason: str) -> None:
self.reason = reason
def __repr__(self) -> str:
name = self.__class__.__name__
return f'<BuildResult.{name}: {self.reason!r}>'
del successful, staged, failed, skipped
在局部判定全局变量的类型
如下代码中的 assert 会被认为不成立从而通过检查并跳过 reveal_type:[2]
from typing import Optional
class Global:
attr: Optional[int] = None
G = Global()
def f() -> None:
G.attr = 1
def t() -> None:
G.attr = None
f()
assert G.attr is not None
reveal_type(G)