繁体   English   中英

使用存根文件提供类似OrderedSet [int]的类型而不修改有序集库

[英]Provide OrderedSet[int] like types using stub file without modifying ordered-set library

我为有序集提供了类型提示。 问题是尽管我在ordered_set.pyi文件中有以下几行:

from typing import MutableSet, TypeVar, Sequence

T = TypeVar('T')

class OrderedSet(MutableSet[T], Sequence[T]):
    ...

我不能写:

IntOrderedSet = OrderedSet[int]

在我的代码中,Python提出:

TypeError: 'ABCMeta' object is not subscriptable

它发生的原因是在ordered_set.py OrderedSet定义为:

from collections.abc import MutableSet, Sequence

class OrderedSet(MutableSet, Sequence):
    ...

我做了一个带有提交的PR,它改变了OrderedSet来继承输入类 ,但是ordered-set所有者拒绝接受它,因为他说:

在代码中导入键入会为代码添加安装时依赖性和运行时成本。 ordered_set作为单个模块获得了6年没有依赖关系。 有人可以决定他们不想与setuptools做任何事情,只是在他们的PYTHONPATH上删除ordered_set,它仍然可以工作。 我不想失去那种类型。

有没有办法,在不修改库ordered_set.py文件的情况下支持OrderedSet[int]类型?

我所知道的唯一解决方法是定义任何自定义类型别名,使它们仅在类型检查时存在,而不是在运行时存在。

为此,您需要:

  1. if typing.TYPE_CHECKING: blocks,则在里面定义任何类型的别名。 typing.TYPE_CHECKING块在运行时始终为false,并通过类型检查器视为true。
  2. 确保您要么将所有类型提示都设置为字符串 - 或者,如果您使用的是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中的内容if TYPE_CHECKING块。

最终的解决方案是首先不要定义IntOrderedSet类型。 这让我们跳过hack 1而只需要使用hack 2(这不是一个黑客攻击 - 它将在几年内成为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这样的类型检查器会根据我们最终使用该变量的方式自动推断出正确的类型。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM