Предоставьте OrderedSet [int] подобные типы, используя стаб-файл без изменения библиотеки упорядоченных наборов

1

Я способствовал намекам типа для упорядоченного набора библиотеки. Проблема в том, что, несмотря на то, что у меня есть следующие строки в файле 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 и просто отбрасывают order_set на PYTHONPATH, и это все равно будет работать. Мне бы очень хотелось потерять эти типы.

Есть ли способ поддерживать OrderedSet[int] без изменения библиотеки ordered_set.py?

Теги:
python-3.x
type-hinting
typehints

1 ответ

2
Лучший ответ

Единственным обходным решением, о котором я знаю, является определение любых пользовательских псевдонимов типа, которые они существуют только во время проверки типа и никогда во время выполнения.

Для этого вам необходимо:

  1. Определите любые псевдонимы типов внутри, if typing.TYPE_CHECKING: блокирует. Блок typing.TYPE_CHECKING всегда является ложным во время выполнения и рассматривается как истинный с помощью typing.TYPE_CHECKING типов.
  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, мы можем обойтись без материала строки и определить 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 в первую очередь. Это позволяет нам пропустить взломать 1, а только использовать хак 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 автоматически определяли бы правильный тип для нас, основываясь на том, как мы в конечном итоге используем эту переменную.

  • 0
    Спасибо! Не знал об обоих взломах. Работает как шарм.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню