问题描述
这是我的测试脚本:
class A:
def __init__(self,config: dict) -> None:
self.config = config
def test_func(a: int) -> None:
pass
main_config = {"a": "x"}
a = A(config=main_config)
# value direct
test_func(1) # line 14
test_func("b") # line 15
# value with wrong type from dict
test_func(main_config["a"]) # line 18
test_func(main_config.get("a")) # line 19
# value with wrong type from dict in class instance
test_func(a.config["a"]) # line 22
test_func(a.config.get("a")) # line 23
如果我用 mypy (0.910) 测试它,我会得到以下结果:
> mypy test.py
test.py:15: error: Argument 1 to "test_func" has incompatible type "str"; expected "int"
tests.py:18: error: Argument 1 to "test_func" has incompatible type "str"; expected "int"
tests.py:19: error: Argument 1 to "test_func" has incompatible type "Optional[str]"; expected "int"
tests.py:23: error: Argument 1 to "test_func" has incompatible type "Optional[Any]"; expected "int"
Found 4 errors in 1 file (checked 1 source file)
为什么 mypy 错过/不报告第 22 行的电话?
解决方法
只是一个假设:
dict.__getitem__()
(又名 a.config[...]
)没有类型注释。虽然 dict.get
有:
def get(self,key: _KT) -> Optional[_VT_co]: ...
我的假设的简单证明:
from typing import Optional,Any
def test_func(a: int) -> None:
pass
def foo(a):
if a == 1:
return 123
elif a == 2:
return 'asd'
else:
raise ValueError
def foo_typed(a) -> Optional[Any]:
if a == 1:
return 123
elif a == 2:
return 'asd'
else:
return None
test_func(foo(2))
test_func(foo_typed(2)) # line 26
仅生产:
main.py:26: error: Argument 1 to "test_func" has incompatible type "Optional[Any]"; expected "int"
即使 foo(2)
返回 str
ing。