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

Я добавил подсказки для библиотеки упорядоченных наборов. Проблема в том, что, несмотря на то, что у меня есть следующие строки в 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.pyOrderedSet определяется как:

from collections.abc import MutableSet, Sequence

class OrderedSet(MutableSet, Sequence):
    ...

Я сделал пиар с коммитом, который меняет OrderedSet класс, наследуемый от набирающих классов, но ordered-set Владелец отказался принять его, потому что, как он сказал:

Импорт ввода в коде добавляет зависимость времени установки и стоимость времени выполнения в код. упорядоченный_сет получен как единый модуль без зависимостей в течение 6 лет. Кто-то может решить, что он не хочет иметь ничего общего с setuptools, и просто сбросить order_set на PYTHONPATH, и он все равно будет работать. Я бы не хотел потерять это из-за типов.

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

1 ответ

Решение

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

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

  1. Определите псевдонимы любого типа внутри if typing.TYPE_CHECKING: блоки. typing.TYPE_CHECKING block всегда имеет значение 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 блок.

Окончательное решение будет просто не определять 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, автоматически выведут для нас правильный тип в зависимости от того, как мы в итоге будем использовать эту переменную.

Другие вопросы по тегам