Python 使用存根文件提供OrderedSet[int]类类型,而不修改OrderedSet库

Python 使用存根文件提供OrderedSet[int]类类型,而不修改OrderedSet库,python,python-3.x,type-hinting,typehints,ordered-set,Python,Python 3.x,Type Hinting,Typehints,Ordered Set,我已经输入了库的提示。问题是,尽管我在ordered_set.pyi文件中有以下几行代码: 输入import MutableSet、TypeVar、Sequence T=TypeVar('T') 类OrderedSet(可变表集[T],序列[T]): ... 我不能写: IntOrderedSet=OrderedSet[int] 在我的代码中,Python提出: TypeError:“ABCMeta”对象不可下标 发生这种情况是因为在ordered_set.pyordered set中定义

我已经输入了库的提示。问题是,尽管我在
ordered_set.pyi
文件中有以下几行代码:

输入import MutableSet、TypeVar、Sequence
T=TypeVar('T')
类OrderedSet(可变表集[T],序列[T]):
...
我不能写:

IntOrderedSet=OrderedSet[int]
在我的代码中,Python提出:

TypeError:“ABCMeta”对象不可下标
发生这种情况是因为在
ordered_set.py
ordered set
中定义为:

from collections.abc导入可变表集,序列
类OrderedSet(可变表集,序列):
...
我用commit做了一个PR,更改了
OrderedSet
类,但是
OrderedSet
所有者拒绝接受它,因为正如他所说:

在代码中输入类型会为代码添加安装时依赖项和运行时成本。ordered_set作为一个单一模块已经使用了6年,没有任何依赖关系。有些人可能决定不想与setuptools有任何关系,只需在他们的PYTHONPATH上删除ordered_set,它仍然可以工作。我不想因为类型而失去这一点


有没有一种方法可以在不修改库
OrderedSet.py
文件的情况下支持类似于
OrderedSet[int]
的类型

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

为此,您需要:

  • 如果键入,请在
    中定义任何类型别名。键入\u检查:
    块。
    typing.TYPE_CHECKING
    块在运行时始终为false,并被类型检查器视为true
  • 确保您的所有类型提示都是字符串——或者,如果您使用的是Python 3.7,请添加来自未来导入注释的
    ,这会自动完成。也就是说,首先要避免计算类型提示
  • 例如,在您的特定设置中,您可以在某个地方为OrderedSet库提供存根,然后编写如下所示的代码(假设Python 3.7+):

    或者,如果您使用的是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\u 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这样的类型检查器可能会根据我们最终使用该变量的方式自动推断出正确的类型。

    谢谢!我不知道这两个黑客。工作起来很有魅力。
    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()