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

Универсальный псевдоним GenericAlias в Python

Объекты GenericAlias (добавлен в Python 3.9.) создаются путем подписки на класс (обычно контейнер), например list[int]. Они предназначены в первую очередь для аннотаций типов.

Обычно подписка на объекты-контейнеры вызывает метод объекта __getitem__(). Подписка на классы некоторых контейнеров может вместо этого метода вызывать метод класса __class_getitem__(). Метод класса __class_getitem__() должен возвращать объект универсального псевдонима GenericAlias.

Примечание. Если присутствует метод метакласса класса __getitem__(), то он будет иметь приоритет над методом __class_getitem__(), определенным в классе.

Объект GenericAlias ​​действует как прокси для универсальных типов, реализуя параметризованные универсальные шаблоны - конкретный универсальный экземпляр, который предоставляет типы для элементов контейнера.

Доступ к пользовательскому типу для объекта GenericAlias ​​можно получить из types.GenericAlias ​​и использовать для проверок isinstance(). Его также можно использовать для непосредственного создания объектов GenericAlias.

Выражение T[X, Y, ...]

Создает GenericAlias - обобщенное представление, которое представляет тип T, содержащий элементы типов X, Y и других в зависимости от используемого T.

Например, функция ожидает список, содержащий элементы с float:

def average(values: list[float]) -> float:
    return sum(values) / len(values)

Другой пример сопоставления объектов с использованием словаря dict, который является универсальным типом, ожидающим двух параметров типа, представляющих тип ключа key и тип значения value.

В этом примере функция ожидает dict с ключами типа str и значениями типа int:

def send_post_request(url: str, body: dict[str, int]) -> None:
    ...

Новое в Python 3.9.

Содержание:

Использование типа GenericAlias.

Встроенные функции isinstance() и issubclass() не принимают типы GenericAlias ​​в качестве второго аргумента:

>>> isinstance([1, 2], list[str])
# Traceback (most recent call last):
#   File "<stdin>", line 1, in <module>
# TypeError: isinstance() argument 2 cannot be a parameterized generic

Среда выполнения Python не применяет аннотации типов. Это распространяется на универсальные типы и их параметры типа. При создании объекта из GenericAlias ​​элементы контейнера не проверяются на соответствие их типу.

Например, следующий код не рекомендуется к использованию, но он будет работать без ошибок:

>>> t = list[str]
>>> t([1, 2, 3])
# [1, 2, 3]

Кроме того, параметризованные универсальные шаблоны стирают параметры типа во время создания объекта:

>>> t = list[str]
>>> type(t)
# <class 'types.GenericAlias'>

>>> l = t()
>>> type(l)
# <class 'list'>

Вызов функций repr() или str() для универсального типа показывает параметризованный тип:

>>> repr(list[int])
# 'list[int]'

>>> str(list[int])
# 'list[int]'

Метод дженериков __getitem__() вызовет исключение, во избежание таких ошибок, как dict[str][str]:

>>> dict[str][str]
# Traceback (most recent call last):
#   File "<stdin>", line 1, in <module>
# TypeError: There are no type variables left in dict[str]

Однако такие выражения действительны при использовании типов переменных. В индексе должно быть столько элементов, сколько есть элементов типов переменных в __args__ объекта GenericAlias.

>>> from typing import TypeVar
>>> Y = TypeVar('Y')
>>> dict[str, Y][int]
dict[str, int]

Стандартные коллекции универсальных типов:

  • tuple,
  • list,
  • dict,
  • set,
  • frozenset,
  • type,
  • collections.deque,
  • collections.defaultdict,
  • collections.OrderedDict,
  • collections.Counter,
  • collections.ChainMap,
  • collections.abc.Awaitable,
  • collections.abc.Coroutine,
  • collections.abc.AsyncIterable,
  • collections.abc.AsyncIterator,
  • collections.abc.AsyncGenerator,
  • collections.abc.Iterable,
  • collections.abc.Iterator,
  • collections.abc.Generator,
  • collections.abc.Reversible,
  • collections.abc.Container,
  • collections.abc.Collection,
  • collections.abc.Callable,
  • collections.abc.Set,
  • collections.abc.MutableSet,
  • collections.abc.Mapping,
  • collections.abc.MutableMapping,
  • collections.abc.Sequence,
  • collections.abc.MutableSequence,
  • collections.abc.ByteString,
  • collections.abc.MappingView,
  • collections.abc.KeysView,
  • collections.abc.ItemsView,
  • collections.abc.ValuesView,
  • contextlib.AbstractContextManager,
  • contextlib.AbstractAsyncContextManager,
  • re.Pattern,
  • re.Match.

Специальные атрибуты универсального псевдонима.

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

genericalias.__origin__:

Этот атрибут указывает на непараметрический универсальный класс:

>>> list[int].__origin__
# <class 'list'>

genericalias.__args__:

Этот атрибут представляет собой кортеж универсальных типов (возможно, длиной 1), переданный исходному методу __class_getitem__() универсального контейнера:

>>> dict[str, list[int]].__args__
# (<class 'str'>, list[int])

genericalias.__parameters__:

Этот атрибут представляет собой лениво вычисляемый кортеж (возможно, пустой) переменных уникального типа, найденных в __args__:

>>> from typing import TypeVar

>>> T = TypeVar('T')
>>> list[T].__parameters__
# (~T,)