Два метода очень далеки от эквивалентности. Вы должны избегать думать о TypeVars как о простых псевдонимах - скорее, это более специальные формы, которые вы используете, когда хотите сделать свои функции универсальными .
Проще всего объяснить, что такое "универсальная функция" на примере. Предположим, вы хотите написать функцию, которая принимает некоторый объект (любой объект!) И возвращает другой объект точно такого же типа . Как бы вы это сделали?
Один из способов, который мы могли бы сделать, это попробовать object
:
def identity(x: object) -> object:
return x
Это сближает нас, поскольку наша identity
функция может, по крайней мере, принимать буквально все что угодно (поскольку все типы наследуются от object
в Python). Однако это решение имеет недостатки: если мы передадим int, мы получим обратно object
, а это не то, что мы хотим.
Скорее нам нужен способ проверки типов, чтобы понять, что между этими двумя типами есть «связь». Именно здесь TypeVar
пригодится:
T = TypeVar('T')
def identity(x: T) -> T:
return x
Наш TypeVar 'T' в этом случае действует как "заполнитель", который может быть связан с любым типом, который мы хотим. Поэтому, если мы сделаем identity(3)
, T
будет привязан к int
- поэтому средство проверки типов поймет, что тип возвращаемого значения также должен быть int
!
И если мы будем использовать T
несколько раз в наших подсказках типов параметров, средство проверки типов будет следить за тем, чтобы типы всегда были одинаковыми.
Итак, что делает приведенное ниже выражение?
IntOrNone_1 = typing.TypeVar('IntOrNone_1', int, None)
Оказывается, иногда полезно добавить ограничений к нашему специальному типу заполнителя. Например, вы ограничили IntOrNone_1
, чтобы его можно было связать только с int
или None
, а не с другими типами.
И, наконец, чтобы ответить на ваш последний вопрос: в приведенных вами примерах вы обязательно должны использовать Union, а не TypeVars.
Независимо от того, используете ли вы Union или псевдоним типа для Union, это действительно вопрос личного вкуса, но если вам не нужно это "заполнитель" или "универсальное" поведение, вам не следует использовать TypeVars.
В mypy docs есть раздел об общих шаблонах , если вы хотите узнать больше о том, как использовать TypeVars. Он охватывает несколько вещей, которые я пропустил, в том числе как создавать универсальные классы (а не только универсальные функции).