在以下情况下,我似乎不了解Mypy的行为。此问题的代码已简化
import typing as t
...
self._store:t.Dict[str,str] = dict()
...
def set_kv(self, key:str, value:int)->t.Any:
assert isinstance(key, six.string_types)
assert isinstance(value, six.string_types)
with self.__lock.write():
self.__store[key] = value
self.__persist()
我通过运行以下命令使用mypy测试此代码
mypy docido_sdk/index/test.py --ignore-missing-imports --follow-imports=error --strict-optional
现在理想情况下,这应该在第self.__store[key]= value
行引发错误。但事实并非如此。
当我删除assert isinstance(value, six.string_types)
时,它只会引发错误。 isinstance是下面给出的简化函数
def isinstance(__o: object, __t: Union[type, Tuple[Union[type, Tuple], ...]]) -> bool: ...
这是mypy的错误或预期行为,因为如果我正确理解isinstance
不会影响对value
类型的mypy的理解。
答案 0 :(得分:2)
调用isinstance()
时,您将在运行时声明value
类型。
在对isinstance()
的调用之前,mypy认为value
是int
,但实际上在运行时可能有所不同。在isinstance()
调用之后,value
必须是str
。
mypy知道isinstance()
,因此将其视为显式指令来覆盖其对value
的了解并相应地更新其模型。
同样,如果您有value: Union[int, str]
,则在检查if isinstance(value, str): ...
之后,mypy可以更新其对宇宙的视图,并知道value
现在是str
而不是{{1 }}。在这种情况下,这似乎更直观。
这里的问题是,可能的类型不相交,因此mypy仅将类型作为唯一的类型:int
。
顺便说一句,打字稿会更好地处理这种情况,因为它有类型str
的这种情况永远都不会发生,并且当您意外地对never
值进行操作时会产生错误。
Mypy没有这个概念,因此它不能很好地解决此类问题,因为它实际上可能是故意的:类型系统仅提供提示,因此您可能有合理的代码使运行时断言能够处理案例类型假设错误的地方。
答案 1 :(得分:1)
这似乎是mypy的预期行为:mypy确实使用isinstance
调用类型推断,而mypy不会在无法访问的代码中引发类型错误。
根据current documentation,mypy使用isinstance
检查来推断变量的类型(尽管不是type(o) is ...
之类的表达式)。它给出了以下示例:
def f(o: object) -> None:
if isinstance(o, int): # Mypy understands isinstance checks
g(o + 1) # Okay; type of o is inferred as int here
...
仅显示o
为int
时才能访问的代码。 Mypy意识到了这一点,并假设o
是int
。这是合理的,因为如果代码不正确,则代码将无法运行。
在您的代码中,仅当self.__store[key] = value
是value
时才能访问str
(在Python 3中,six.string_types
是(str,)
)。您的代码不同之处在于断言不可能为真。因此,代码根本无法运行。因此,无法运行该代码并导致类型错误。
Elsewhere in the documentation,他们给出了mypy不进行类型检查不可达代码的示例:
from typing import NoReturn def stop() -> NoReturn: raise Exception('no way')
Mypy将确保注释为返回
NoReturn
的函数永远不会隐式或显式地返回。 Mypy还将认识到调用此类函数后的代码无法访问,并且将相应地起作用:def f(x: int) -> int: if x == 0: return x stop() return 'whatever works' # No error in an unreachable block
请注意他们使用的措辞:“将相应地表现”。这就是许多人希望类型检查器对无法访问的代码执行的操作。