簡體   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