Предположим, я хочу ввести подсказку для универсальной функции в Python до версии 3.12, когда был введен новый синтаксис параметров:
def max[T](args: Iterable[T]) -> T:
...
Затем у меня есть возможность использовать подсказки строкового типа:
def max(args: Iterable["T"]) -> "T":
...
Или введите переменные:
T = TypeVar("T")
def max(args: Iterable[T]) -> T:
...
Мне больше нравится последний подход, но введение дополнительной глобальной переменной определенно является недостатком. Я решил объединить хинтинг универсального типа с оператором моржа, вот так:
def max(args: Iterable[T := TypeVar("T")]) -> T:
...
Или
def max(args: Iterable[T := int | float]) -> T:
...
Подобный код выполняется без ошибок, но некоторые библиотеки типизации не распознают этот синтаксис. Каковы недостатки написания такого кода?
T по-прежнему глобальный; вы просто переместили определение и засорили сигнатуру функции. Хуже того, не будет очевидно, что вы переопределили T, когда попробуете тот же трюк в другой функции.
«Тогда у меня есть возможность использовать подсказки строкового типа:» На самом деле это работает не так, как другие примеры. Он просто позволяет избежать ошибки во время выполнения, но не создает переменную типа T, как в других примерах. Аналогично, T := int | float не определяет переменную типа.
«Подобный код выполняется без ошибок, но некоторые библиотеки типов не распознают этот синтаксис». Вы действительно нашли какую-либо программу проверки типов, которая принимает это? И MyPy, и PyLance отвергают варианты моржа.
@chepner Правда, я не осознавал, что T всё равно будет глобальным. Но переопределение T не является проблемой, поскольку я никогда не получаю доступа к его значению, и оно генерирует сигнатуры функций, как и ожидалось. Загромождение сигнатуры является недостатком, но, с другой стороны, объединение определения typevar вместе с определением функции имеет смысл.






Я бы выбрал совместимость со стандартными инструментами: это убережет ваших коллег от многих сюрпризов. Так вот: никаких моржей в намеках типа :).
Видимо, по какой-то причине это не вошло в документацию, но ваш вопрос рассмотрен в PEP484:
Выражение
TypeVar()всегда должно быть напрямую присвоено переменной (его не следует использовать как часть более крупного выражения). АргументTypeVar()должен быть строкой, равной имени переменной, которой он присвоен. Переменные типа не должны переопределяться.
Таким образом, специалисты по проверке типов должны отклонить предложенный вами фрагмент. mypyделает , Pyright тоже делает , и Pyre тоже делает.
Итак, основным недостатком написания такого кода является тот факт, что такой код несовместим и неправильно интерпретируется средствами проверки типов.
Этот вопрос следует отредактировать, чтобы он сосредоточился только на одной проблеме и не требовал рекомендаций.