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

Аннотация TypeVarTuple модуля typing в Python

Аннотация типов структур, подобных массивам в Python

В Python 3.11 добавлена аннотация typing.TypeVarTuple, которая представляет собой тип переменной кортеж. Специализированная форма переменной типа, которая позволяет использовать вариативные обобщения.

Другими словами, аннотация typing.TypeVarTuple - это переменная типа с переменным числом аргументов, позволяющая использовать обобщения с переменным числом переменных.

В Python 3.12 кортежи переменных типа могут быть объявлены в списках параметров типа, используя одну звездочку * перед именем:

def move_first_element_to_last[T, *Ts](tup: tuple[T, *Ts]) -> tuple[*Ts, T]:
    return (*tup[1:], tup[0])

Изменено в версии 3.12: кортежи переменных типа теперь можно объявлять с использованием синтаксиса параметров типа.

Или явным вызовом конструктора typing.TypeVarTuple:

from typing import TypeVar, TypeVarTuple

T = TypeVar('T')
Ts = TypeVarTuple('Ts')

def move_first_element_to_last(tup: tuple[T, *Ts]) -> tuple[*Ts, T]:
    return (*tup[1:], tup[0])

Переменная обычного типа typing.TypeVar позволяет параметризовать один тип. Кортеж переменных типа typing.TypeVarTuple, напротив, допускает параметризацию с произвольным количеством типов, действуя как произвольное количество переменных типа, заключенных в кортеж. Например:

# `T` привязан к `int`, `Ts` привязан к `()`
# Возвращаемое значение `(1,)` имеет тип `tuple[int]`
move_first_element_to_last(tup=(1,))

# `T` привязан к `int`, `Ts` привязан к `(str,)`
# Возвращаемое значение `('spam', 1)` имеет тип `tuple[str, int]`
move_first_element_to_last(tup=(1, 'spam'))

# `T` привязан к `int`, `Ts` привязан к `(str, float)`
# Возвращаемое значение `('spam', 3.0, 1)` имеет тип `tuple[str, float, int]`
move_first_element_to_last(tup=(1, 'spam', 3.0))

# Ошибка при вводе (и ошибка во время выполнения)
# потому что `tuple[()]` несовместим с `tuple[T, *Ts]`
# (требуется хотя бы один элемент)
move_first_element_to_last(tup=())

Обратите внимание на использование оператора распаковки * в tuple[T, *Ts]. Концептуально можно думать о Ts как о кортеже переменного типа (T1, T2,...). tuple[T, *Ts] станет тогда tuple[T, *(T1, T2, ...)], что эквивалентно tuple[T, T1, T2, ...]. (Обратите внимание, что в более старых версиях Python это может быть написано с использованием typing.Unpack вместо Unpack[Ts].)

Кортежи переменных типа всегда должны быть распакованы звездочкой (*). Это помогает отличить кортежи переменных типа от переменных обычного типа:

x: Ts          # Недействительно
x: tuple[Ts]   # Недействительно
x: tuple[*Ts]  # Правильный способ

Кортежи переменных типа могут использоваться в тех же контекстах, что и переменные обычного типа. Например, в определениях классов, аргументах и ​​возвращаемых типах:

Shape = TypeVarTuple('Shape')
class Array(Generic[*Shape]):
    def __getitem__(self, key: tuple[*Shape]) -> float: ...
    def __abs__(self) -> Array[*Shape]: ...
    def get_shape(self) -> tuple[*Shape]: ...

Кортежи переменных типа можно успешно комбинировать с переменными обычного типа:

DType = TypeVar('DType')

# Это хорошо
class Array(Generic[DType, *Shape]):
    pass

# Это тоже неплохо
class Array2(Generic[*Shape, DType]):
    pass

# хорошо
float_array_1d: Array[float, Height] = Array()
# это тоже хорошо
int_array_2d: Array[int, Height, Width] = Array()

Обратите внимание, что не более одного кортежа переменных типа может присутствовать в одном списке аргументов типа или параметров типа:

# Недействительно
x: tuple[*Ts, *Ts]

# Недействительно
class Array(Generic[*Shape, *Shape]):
    pass

Наконец, в качестве аннотации типа *args можно использовать распакованный кортеж переменных типа:

def call_soon(
        callback: Callable[[*Ts], None],
        *args: *Ts
) -> None:
    ...
    callback(*args)

В отличие от аннотаций, например, *args: int, означающих, что все аргументы имеют тип int, аннотация типа *args: *Ts позволяет ссылаться на типы отдельных аргументов в *args. Это позволяет гарантировать, что типы *args, переданные в call_soon(), соответствуют типам (позиционных) аргументов функции callback().

Аннотация TypeVarTuple имеет атрибут:

TypeVarTuple.__name__:

Атрибут TypeVarTuple.__name__ представляет собой имя кортежа переменной типа.

Новое в Python 3.11.