如何解决mypy检测方法设置属性时的「Statement is unreachable」错误?
让Mypy识别属性类型变更并取消不可达代码警告
问题描述
假设有如下测试代码:
class Foo: def __init__(self): self.value: int | None = None def set_value(self, value: int | None): self.value = value def test_foo(): foo = Foo() assert foo.value is None foo.set_value(1) assert isinstance(foo.value, int) assert foo.value == 1 # unreachable
测试流程:
- 检查
foo.value初始值为None - 调用
set_value方法设置属性值为整数1 - 验证属性值已变更为整数并等于1
当使用Mypy 1.9.0版本(撰写时最新版)且开启warn_unreachable配置时,会触发如下错误:
(venv) niko@niko-ubuntu-home:~/code/myproj$ python -m mypy tests/test_foo.py tests/test_foo.py:16: error: Statement is unreachable [unreachable] Found 1 error in 1 file (checked 1 source file)
已尝试方案
曾尝试使用safe-assert库改写测试代码,期望解决类型推断问题:
from safe_assert import safe_assert def test_foo(): foo = Foo() safe_assert(foo.value is None) foo.set_value(1) safe_assert(isinstance(foo.value, int)) assert foo.value == 1
但在safe-assert 0.4.0版本中问题仍存在,Mypy和VS Code Pylance均判定foo.set_value(1)语句不可达。
更新说明:
safe_assert0.5.0版本已修复该问题
解决方法
以下几种方式可以让Mypy正确识别foo.value的类型变更,避免不可达代码警告:
1. 升级safe-assert到最新版本
直接将safe-assert升级至0.5.0及以上版本,该版本修复了类型推断相关的问题,既能保留断言的类型窄化效果,又能让Mypy正确识别后续代码的可达性。
2. 手动添加类型断言
如果不想依赖第三方库,可以通过显式类型注解或cast函数告诉Mypy属性的具体类型:
方式一:显式变量注解
def test_foo(): foo = Foo() assert foo.value is None foo.set_value(1) assert isinstance(foo.value, int) # 显式指定变量类型,帮助Mypy推断 foo_value: int = foo.value assert foo_value == 1
方式二:使用cast函数
from typing import cast def test_foo(): foo = Foo() assert foo.value is None foo.set_value(1) assert isinstance(foo.value, int) # 强制类型转换,告知Mypy当前属性的类型 foo.value = cast(int, foo.value) assert foo.value == 1
3. 优化类方法的类型注解
通过给set_value方法添加重载注解,让Mypy能更精确地推断属性类型变化:
from typing import overload class Foo: def __init__(self): self.value: int | None = None @overload def set_value(self, value: int) -> None: ... @overload def set_value(self, value: None) -> None: ... def set_value(self, value: int | None): self.value = value
当调用foo.set_value(1)时,Mypy会根据重载注解推断出foo.value此时为int类型,后续断言不会被判定为不可达。
4. 临时屏蔽警告(不推荐)
如果仅需临时绕过该警告,可以在代码中添加忽略注释:
assert foo.value == 1 # type: ignore[unreachable]
或在Mypy配置文件中针对特定文件关闭warn_unreachable,但这种方式会错过真正的不可达代码问题,不建议长期使用。
内容的提问来源于stack exchange,提问作者Niko Fohr
相关产品推荐
相关产品推荐

