首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用存根文件提供类似OrderedSet[int]的类型,而无需修改有序集库

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

Stack Overflow用户
提问于 2018-09-29 22:33:00
回答 1查看 237关注 0票数 3

我为ordered-set库提供了contributed类型提示。问题是,尽管我在ordered_set.pyi文件中有以下几行:

代码语言:javascript
复制
from typing import MutableSet, TypeVar, Sequence

T = TypeVar('T')

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

我不能写:

代码语言:javascript
复制
IntOrderedSet = OrderedSet[int]

在我的代码中,Python引发了:

代码语言:javascript
复制
TypeError: 'ABCMeta' object is not subscriptable

之所以会发生这种情况,是因为在ordered_set.pyOrderedSet被定义为:

代码语言:javascript
复制
from collections.abc import MutableSet, Sequence

class OrderedSet(MutableSet, Sequence):
    ...

我提交了一个PR,更改了OrderedSet类的to inherit from typing classes,但ordered-set的所有者拒绝接受它,因为他说:

在代码中导入类型会在代码中添加安装时依赖项和运行时开销。ordered_set作为一个独立的模块已经存在6年了。有些人可能决定他们不想使用setuptools,只需将ordered_set放在他们的PYTHONPATH上,它仍然可以工作。我不想因为类型而失去这一点。

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

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-09-30 00:36:28

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

要做到这一点,您需要:

  1. if typing.TYPE_CHECKING:块中定义任何类型别名。
  2. 确保您的所有类型提示都是字符串--或者,如果您使用的是Python3.7,则添加from __future__ import annotations,它会自动执行此操作。也就是说,避免从一开始就必须计算类型提示。

例如,在您的特定设置中,您可以在某个地方为OrderedSet库贡献存根,然后编写如下代码(假设Python 3.7+):

代码语言:javascript
复制
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或更低版本:

代码语言:javascript
复制
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定义为在类型检查时与运行时略有不同的东西。例如:

代码语言:javascript
复制
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中的默认行为)。

例如,我们可以这样做:

代码语言:javascript
复制
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之类的类型检查器可能会根据我们最终如何使用该变量自动推断出正确的类型。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/52569356

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档