我知道的唯一解决方法是定义任何自定义类型别名,以便它们仅在类型检查时存在,而从不在运行时存在。
为此,您需要:
if typing.TYPE_CHECKING:
在块内定义任何类型别名。该typing.TYPE_CHECKING
块在运行时始终为假,并被类型检查器视为真。
- 确保您的所有类型提示都是字符串——或者,如果您使用的是 Python 3.7,请添加
from __future__ import annotations
,它会自动执行此操作。也就是说,首先要避免评估类型提示。
因此,例如,在您的特定设置中,您可以在某处为 OrderedSet 库贡献存根,然后将代码编写成如下所示(假设 Python 3.7+):
from __future__ import annotations
from typing import TYPE_CHECKING
from ordered_set import OrderedSet
# Basically equivalent to `if False`
if TYPE_CHECKING:
IntOrderedSet = OrderedSet[Int]
def expects_int_ordered_set(x: IntOrderedSet) -> None:
# blah
some_ordered_set: IntOrderedSet = OrderedSet()
或者,如果您使用的是 Python 3.6 或更低版本:
from typing import TYPE_CHECKING
from ordered_set import OrderedSet
if TYPE_CHECKING:
IntOrderedSet = OrderedSet[Int]
def expects_int_ordered_set(x: 'IntOrderedSet') -> None:
# blah
some_ordered_set: 'IntOrderedSet' = OrderedSet()
如果你可以稍微撒谎,我们可以省去字符串的东西,并IntOrderedSet
在类型检查时与运行时定义稍微不同的东西。例如:
from typing import TYPE_CHECKING
from ordered_set import OrderedSet
if TYPE_CHECKING:
IntOrderedSet = OrderedSet[Int]
else:
IntOrderedSet = OrderedSet
def expects_int_ordered_set(x: IntOrderedSet) -> None:
# blah
some_ordered_set = IntOrderedSet()
不过,请确保在执行此操作时要小心——类型检查器不会检查“else”块中的任何内容/不会检查以确保您在那里所做的任何事情与该if TYPE_CHECKING
块中的内容一致。
最终的解决方案是首先不定义IntOrderedSet
类型。这让我们可以跳过 hack 1,而只需要使用 hack 2(这并不是一个 hack——几年后它将成为 Python 中的默认行为)。
例如,我们可以这样做:
from __future__ import annotations
from ordered_set import OrderedSet
def expects_int_ordered_set(x: OrderedSet[int]) -> None:
# blah
some_ordered_set: OrderedSet[int] = OrderedSet()
根据上下文,可能我什至不需要在最后一个变量声明中添加注释。在这里,我们这样做了,但是如果我们在函数内部定义该变量,则像 mypy 这样的类型检查器可能会根据我们最终使用该变量的方式自动为我们推断出正确的类型。