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

Новый синтаксис типизации списка параметров/аргументов в Python3.12

Добавлено в Python 3.12.

Изменено в Python 3.13: добавлена поддержка значений по умолчанию (см. PEP 696).

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

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

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 недоступно в области видимости модуля. Ниже семантика универсальных объектов описана более точно. Область действия типов параметров/аргументов моделируется с помощью специальной функции (технической области аннотации), которая завершает создание универсального объекта.

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

Типы списков параметров/аргументов бывают трех видов:

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

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

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

typing.TypeVarTuples и typing.ParamSpecs не могут иметь границ или ограничений.

Все три разновидности типов для списка параметров/аргументов также могут иметь значение по умолчанию, которое используется, когда тип параметра/аргумента явно не указан. Это добавляется путем одного знака равенства (=), за которым следует выражение. Подобно границам и ограничениям типа переменных, значение по умолчанию не оценивается при создании объекта, а только при доступе к атрибуту __default__ типа параметра . Для этого значение по умолчанию оценивается в отдельной области аннотации. Если для типа параметра/аргумента не указано значение по умолчанию, то атрибуту __default__ присваивается специальный тип сторожевого typing.NoDefault.

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

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