如何告知MyPy调用指定方法后变量不可能为None?
mypy自定义非空校验不生效问题解决方案
问题根因
mypy的类型窄化逻辑默认仅作用于当前作用域的直接判断,不会自动关联自定义校验方法的返回值和实例属性的类型状态,因此你通过IsDataValid方法做的判断无法让mypy识别到后续self.data不可能为None。
可行方案
方案1:使用TypeGuard标注校验方法(推荐)
这是最符合类型规范的方案,通过TypeGuard标注你的校验方法,明确告知mypy:当该方法返回True时,当前实例的data属性一定为str类型。
Python 3.11+可直接从标准库typing导入TypeGuard和Self,低版本Python需从typing-extensions导入对应类型。修改后的代码示例如下:
from typing import Optional, TypeGuard, Self class Foo: data: Optional[str] def __init__(self): self.data = None def IsDataValid(self) -> TypeGuard[Self]: return self.data is not None def SetData(self, data: str) -> None: self.data = data def GetData(self) -> str: if not self.IsDataValid(): raise ValueError("Invalid data") return self.data
方案2:增加显式窄化断言
如果不想修改原有校验方法的类型标注,可以在校验调用后加一行显式断言,仅用于mypy类型提示,同时也能做运行时二次校验:
def GetData(self) -> str: if not self.IsDataValid(): raise ValueError("Invalid data") assert self.data is not None return self.data
该方案改动量极小,无需引入额外依赖,适合临时快速修复。
方案3:改造校验方法为直接抛错的工具方法
将返回布尔值的校验方法改为无效直接抛异常的形式,mypy会识别到只要方法正常返回,就说明data已经是有效状态:
def EnsureDataValid(self) -> None: if self.data is None: raise ValueError("Invalid data") def GetData(self) -> str: self.EnsureDataValid() return self.data
该方案完全避免了后续重复编写抛错逻辑,适合多位置需要做合法校验的场景。
内容的提问来源于stack exchange,提问作者yuko
相关产品推荐
相关产品推荐

