Сообщить об ошибке.

Определение списка параметров типа в Python

Синтаксис:

type_params  ::=  "[" type_param ("," type_param)* "]"
type_param   ::=  typevar | typevartuple | paramspec
typevar      ::=  identifier (":" expression)?
typevartuple ::=  "*" identifier
paramspec    ::=  "**" identifier

Описание:

Новое в Python 3.12.

Функции (включая сопрограммы), классы и псевдонимы типов могут содержать список параметров типа:

def max[T](args: list[T]) -> T:
    ...

async def amax[T](args: list[T]) -> T:
    ...

class Bag[T]:
    def __iter__(self) -> Iterator[T]:
        ...

    def add(self, arg: T) -> None:
        ...

type ListOrSet[T] = list[T] | set[T]

Семантически это указывает на то, что функция, класс или псевдоним типа являются универсальными для переменной типа. Эта информация в основном используется средствами проверки статических типов, и во время выполнения универсальные объекты ведут себя так же, как их неуниверсальные аналоги.

Параметры типа объявляются в квадратных скобках ([]) сразу после имени функции, класса или псевдонима типа. Параметры типа доступны в пределах области видимости универсального объекта, но не где-либо еще. Таким образом, после объявления def func[T](): pass имя T недоступно в области видимости модуля. Область действия параметров типа моделируется с помощью специальной функции (технически области видимости аннотации), которая завершает создание универсального объекта.

Универсальные функции, классы и псевдонимы типов имеют атрибут TypeAliasType.__type_params__, в котором перечислены их параметры типа.

Параметры типа бывают трех видов:

  • typing.TypeVar, представленный простым именем (например, T). Семантически это представляет один тип для средства проверки типов.
  • typing.TypeVarTuple, представленный именем с префиксом одной звездочки (например, *Ts). Семантически это обозначает кортеж любого числа типов.
  • typing.ParamSpec, представленный именем с префиксом двух звездочек (например, **P). Семантически это обозначает аргументы вызываемого объекта.

Объявления typing.TypeVar могут определять границы и ограничения с помощью двоеточия (:), за которым следует выражение. Одиночное выражение после двоеточия указывает на границу (например, T: int). Семантически это означает, что typing.TypeVar может представлять только типы, которые являются подтипом этой границы. Кортеж выражений в скобках после двоеточия указывает на набор ограничений (например, T: (str, bytes)). Каждый член кортежа должен быть типом (опять же, это не применяется во время выполнения). Переменные ограниченного типа могут принимать только один из типов в списке ограничений.

Для typing.TypeVar, объявленного с использованием синтаксиса списка параметров типа, привязка и ограничения не оцениваются при создании универсального объекта, а только тогда, когда к значению осуществляется явный доступ через атрибуты TypeVar.__bound__ и TypeVar.__constraints__. Для этого границы или ограничения оцениваются в отдельной области видимости аннотаций.

Типы параметров typing.TypeVarTuple и typing.ParamSpec не могут иметь границ или ограничений.

В следующем примере показан полный набор разрешенных объявлений параметров типа:

def overly_generic[
   SimpleTypeVar,
   TypeVarWithBound: int,
   TypeVarWithConstraints: (str, bytes),
   *SimpleTypeVarTuple,
   **SimpleParamSpec,
](
   a: SimpleTypeVar,
   b: TypeVarWithBound,
   c: Callable[SimpleParamSpec, TypeVarWithConstraints],
   *d: SimpleTypeVarTuple,
): ...