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

Тип аннотации TypeVar модуля typing в Python

Типизация универсальных значений переменных

Не используется в аннотациях, являются строительным блоком для создания универсальных типов.

Синтаксис:

from typing import TypeVar

typing.TypeVar(name, *constraints, bound=None, covariant=False, 
               contravariant=False, infer_variance=False)

Параметры:

  • name - имя переменной типа,
  • *constraints - кортеж, содержащий ограничения переменной типа, если таковые имеются,
  • bound=None - подтип/привязка переменной типа, если такой имеется,
  • covariant=False - был ли тип переменной явно помечен как ковариантный,
  • contravariant=False - был ли тип переменной явно помечен как контравариантный,
  • infer_variance=False - следует ли определять отклонение переменной типа с помощью средств проверки типов.

Описание TypeVar() :

Тип аннотации TypeVar() модуля typing представляет собой - возможные типы переменных.

Предпочтительным способом создания переменной типа в Python 3.12 является использование специального синтаксиса для универсальных функций, универсальных классов и псевдонимов универсальных типов:

# T - это `TypeVar`
class Sequence[T]:
    ...

Этот синтаксис также можно использовать для создания переменных связанного и ограниченного типа:

# S - это `TypeVar`, привязанный к `str`
class StrSequence[S: str]:
    ...
# A - это `TypeVar`, ограниченный значением `str` или `bytes`
class StrOrBytesSequence[A: (str, bytes)]:
    ...

При желании и для совместимости с Python<=3.12, переменные типа многократного использования можно создать вручную, например:

T = TypeVar('T')  # Может быть что угодно
A = TypeVar('A', str, bytes)  # Должно быть `str` или `bytes`
S = TypeVar('S', bound=str)  # Может быть любым подтипом `str`

Переменные типа существуют в первую очередь для целей проверки статических типов. Они служат параметрами для универсальных типов, а также для определений универсальных функций и псевдонимов типов. Дополнительно смотрите сведения о типе аннотации typing.Generic.

Универсальные функции работают следующим образом:

def repeat[T](x: T, n: int) -> Sequence[T]:
    """Возвращает список, содержащий n ссылок на x."""
    return [x]*n

def print_capitalized[S: str](x: S) -> S:
    """Печатает x с заглавной буквы и возвращает x."""
    print(x.capitalize())
    return x

def concatenate[A: (str, bytes)](x: A, y: A) -> A:
    """Конкатенация двух объектов `strings` или `bytes`."""
    return x + y

Обратите внимание, что переменные типа могут быть связанными, ограниченными или ни одним из них, но не могут быть одновременно связанными и ограниченными.

Отклонения переменных типа определяется средствами проверки типов, когда они создаются с помощью синтаксиса параметра типа или когда передается infer_variance=True. Созданные вручную переменные типа могут быть явно помечены как ковариантные или контравариантные путем передачи covariant=True или contravariant=True. По умолчанию переменные типа, созданные вручную, являются инвариантными.

Переменные связанного типа и переменные ограниченного типа имеют разную семантику по нескольким важным причинам. Использование переменной связанного типа означает, что TypeVar будет решен с использованием наиболее конкретного возможного типа:

x = print_capitalized('a string')
# выявленный тип - `str`
reveal_type(x)

class StringSubclass(str):
    pass

y = print_capitalized(StringSubclass('another string'))
# выявленный тип - StringSubclass
reveal_type(y)

# ошибка: `int` не является подтипом `str`
z = print_capitalized(45)

Переменные типа могут быть привязаны к конкретным типам, абстрактным типам (ABC или протоколам) и даже к объединениям типов:

# Может быть чем угодно с помощью метода `__abs__`
def print_abs[T: SupportsAbs](arg: T) -> None:
    print("Absolute value:", abs(arg))

# Может быть любым подтипом объединения `str|bytes`
U = TypeVar('U', bound=str|bytes) 
# Может быть что угодно с помощью метода `__abs__`
V = TypeVar('V', bound=SupportsAbs)

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

a = concatenate('one', 'two')
# выявленный тип - `str`
reveal_type(a)

b = concatenate(StringSubclass('one'), StringSubclass('two'))
# выявленный тип - `str`, несмотря на передачу `StringSubclass`
reveal_type(b)

# ошибка: переменная типа 'A' в вызове функции может быть  
# либо строкой, либо байтами , но не обоими одновременно
c = concatenate('one', b'two')

Во время выполнения isinstance(x, T) вызовет TypeError.

  • TypeVar.__name__: имя переменной типа.

  • TypeVar.__covariant__: был ли тип переменной явно помечен как ковариантный.

  • TypeVar.__contravariant__: был ли тип переменной явно помечен как контравариантный.

  • TypeVar.__infer_variance__: следует ли определять отклонение переменной типа с помощью средств проверки типов.

    Новое в Python 3.12.

  • TypeVar.__bound__: подтип/привязка переменной типа, если таковая имеется.

    Изменено в Python 3.12: Для переменных типа, созданных с помощью синтаксиса параметра типа, привязка вычисляется только при обращении к атрибуту, а не при создании переменной типа.

  • TypeVar.__constraints__: кортеж, содержащий ограничения переменной типа, если таковые имеются.

    Изменено в Python 3.12: Для переменных типа, созданных с помощью синтаксиса параметра типа, ограничения вычисляются только при обращении к атрибуту, а не при создании переменной типа.

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