Spec-Zone.ru › Python 3.11

typing — Поддержка подсказок типов

Добавлено в версии 3.5.

Исходный код: Lib/typing.py

Примечание

Среда выполнения Python не проверяет аннотации типов функций и переменных. Их могут использовать сторонние инструменты, например средства статической проверки типов, IDE, линтеры и т. д.

Этот модуль обеспечивает поддержку подсказок типов во время выполнения. Исходную спецификацию системы типизации см. в PEP 484. Упрощённое введение в подсказки типов приведено в PEP 483.

Функция ниже принимает строку и возвращает строку; её аннотации выглядят следующим образом:

def greeting(name: str) -> str:
    return 'Hello ' + name

В функции greeting аргумент name должен иметь тип str, а возвращаемое значение — тип str. В качестве аргументов допускаются подклассы.

В модуль typing часто добавляются новые возможности. Пакет typing_extensions предоставляет обратные порты этих возможностей для более старых версий Python.

Краткий обзор устаревших возможностей и график их устаревания см. в разделе График устаревания основных возможностей.

См. также

«Шпаргалка по типизации»

Краткий обзор подсказок типов (на сайте документации mypy)

Раздел «Справочник по системе типов» в документации mypy

Система типизации Python стандартизирована с помощью PEP, поэтому этот справочник в целом применим к большинству средств проверки типов Python. (Некоторые части могут быть специфичны для mypy.)

«Статическая типизация в Python»

Документация, не привязанная к конкретному средству проверки типов, подготовленная сообществом. В ней подробно описаны возможности системы типов, полезные инструменты, связанные с типизацией, и рекомендации по типизации.

Связанные PEP

После первоначального введения подсказок типов в PEP 484 и PEP 483 ряд PEP изменил и расширил систему аннотаций типов Python:

Полный список PEP
  • PEP 526: Синтаксис аннотаций переменных

    Вводит синтаксис аннотирования переменных вне определений функций и ClassVar

  • PEP 544: Протоколы: структурная подтипизация (статическая утиная типизация)

    Вводит Protocol и декоратор @runtime_checkable

  • PEP 585: Обобщённые подсказки типов для стандартных коллекций

    Вводит types.GenericAlias и возможность использовать классы стандартной библиотеки в качестве обобщённых типов

  • PEP 586: Литеральные типы

    Вводит Literal

  • PEP 589: TypedDict: подсказки типов для словарей с фиксированным набором ключей

    Вводит TypedDict

  • PEP 591: Добавление квалификатора final в типизацию

    Вводит Final и декоратор @final

  • PEP 593: Гибкие аннотации функций и переменных

    Вводит Annotated

  • PEP 604: Allow writing union types as X | Y

    Вводит types.UnionType и возможность использовать оператор побитового ИЛИ | для обозначения объединения типов

  • PEP 612: Переменные спецификации параметров

    Вводит ParamSpec и Concatenate

  • PEP 613: Явные псевдонимы типов

    Вводит TypeAlias

  • PEP 646: Вариативные обобщения

    Вводит TypeVarTuple

  • PEP 647: Определяемые пользователем защитники типов

    Вводит TypeGuard

  • PEP 655: Пометка отдельных элементов TypedDict как обязательных или потенциально отсутствующих

    Вводит Required и NotRequired

  • PEP 673: Тип Self

    Вводит Self

  • PEP 675: Произвольный тип литеральной строки

    Вводит LiteralString

  • PEP 681: Преобразования классов данных

    Вводит декоратор @dataclass_transform


Псевдонимы типов

Псевдоним типа определяется присваиванием типа псевдониму. В этом примере Vector и list[float] будут считаться взаимозаменяемыми синонимами:

Vector = list[float]

def scale(scalar: float, vector: Vector) -> Vector:
    return [scalar * num for num in vector]

# passes type checking; a list of floats qualifies as a Vector.
new_vector = scale(2.0, [1.0, -4.2, 5.4])

Псевдонимы типов полезны для упрощения сложных сигнатур типов. Например:

from collections.abc import Sequence

ConnectionOptions = dict[str, str]
Address = tuple[str, int]
Server = tuple[Address, ConnectionOptions]

def broadcast_message(message: str, servers: Sequence[Server]) -> None:
    ...

# The static type checker will treat the previous type signature as
# being exactly equivalent to this one.
def broadcast_message(
        message: str,
        servers: Sequence[tuple[tuple[str, int], dict[str, str]]]) -> None:
    ...

Псевдонимы типов можно помечать с помощью TypeAlias, чтобы явно указать, что данное выражение объявляет псевдоним типа, а не выполняет обычное присваивание переменной:

from typing import TypeAlias

Vector: TypeAlias = list[float]

NewType

Используйте вспомогательную функцию NewType, чтобы создавать отдельные типы:

from typing import NewType

UserId = NewType('UserId', int)
some_id = UserId(524313)

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

def get_user_name(user_id: UserId) -> str:
    ...

# passes type checking
user_a = get_user_name(UserId(42351))

# fails type checking; an int is not a UserId
user_b = get_user_name(-1)

Для переменной типа UserId по-прежнему можно выполнять все операции int, но результат всегда будет иметь тип int. Это позволяет передавать UserId везде, где ожидается int, но не даёт случайно создать UserId недопустимым способом:

# 'output' is of type 'int', not 'UserId'
output = UserId(23413) + UserId(54341)

Обратите внимание, что эти проверки выполняются только средством статической проверки типов. Во время выполнения инструкция Derived = NewType('Derived', Base) превращает Derived в вызываемый объект, который сразу возвращает переданный ему параметр. Это означает, что выражение Derived(some_value) не создаёт новый класс и почти не добавляет накладных расходов по сравнению с обычным вызовом функции.

Точнее говоря, выражение some_value is Derived(some_value) всегда истинно во время выполнения.

Создавать подкласс Derived нельзя:

from typing import NewType

UserId = NewType('UserId', int)

# Fails at runtime and does not pass type checking
class AdminUserId(UserId): pass

Однако можно создать NewType на основе «производного» NewType:

from typing import NewType

UserId = NewType('UserId', int)

ProUserId = NewType('ProUserId', UserId)

и проверка типов для ProUserId будет работать ожидаемым образом.

Подробнее см. в PEP 484.

Примечание

Помните, что использование псевдонима типа объявляет два типа эквивалентными. Выражение Alias = Original заставит средство статической проверки типов считать Alias полностью эквивалентным Original во всех случаях. Это полезно, когда нужно упростить сложные сигнатуры типов.

Напротив, NewType объявляет один тип подтипом другого. Выражение Derived = NewType('Derived', Original) заставит средство статической проверки типов считать Derived подклассом Original, а это означает, что значение типа Original нельзя использовать там, где ожидается значение типа Derived. Это полезно, когда нужно предотвратить логические ошибки с минимальными затратами во время выполнения.

Добавлено в версии 3.5.2.

Изменено в версии 3.10: NewType теперь является классом, а не функцией. В результате вызов NewType требует несколько больше затрат во время выполнения, чем вызов обычной функции.

Изменено в версии 3.11: Производительность вызова NewType вернулась к уровню Python 3.9.

Аннотирование вызываемых объектов

Функции — и другие вызываемые объекты — можно аннотировать с помощью collections.abc.Callable или typing.Callable. Callable[[int], str] обозначает функцию, которая принимает один параметр типа int и возвращает значение типа str.

Например:

from collections.abc import Callable, Awaitable

def feeder(get_next_item: Callable[[], str]) -> None:
    ...  # Body

def async_query(on_success: Callable[[int], None],
                on_error: Callable[[int, Exception], None]) -> None:
    ...  # Body

async def on_update(value: str) -> None:
    ...  # Body

callback: Callable[[str], Awaitable[None]] = on_update

В синтаксисе подписки всегда должно использоваться ровно два значения: список аргументов и тип возвращаемого значения. Список аргументов должен быть списком типов, ParamSpec, Concatenate или многоточием. Тип возвращаемого значения должен быть одним типом.

Если в качестве списка аргументов указано буквальное многоточие ..., это означает, что подойдёт вызываемый объект с любым произвольным списком параметров:

def concat(x: str, y: str) -> str:
    return x + y

x: Callable[..., str]
x = str     # OK
x = concat  # Also OK

Callable не позволяет выразить сложные сигнатуры, например функции с переменным числом аргументов, перегруженные функции или функции с параметрами, доступными только по ключевому слову. Однако такие сигнатуры можно выразить, определив класс Protocol с методом __call__():

from collections.abc import Iterable
from typing import Protocol

class Combiner(Protocol):
    def __call__(self, *vals: bytes, maxlen: int | None = None) -> list[bytes]: ...

def batch_proc(data: Iterable[bytes], cb_results: Combiner) -> bytes:
    for item in data:
        ...

def good_cb(*vals: bytes, maxlen: int | None = None) -> list[bytes]:
    ...
def bad_cb(*vals: bytes, maxitems: int | None) -> list[bytes]:
    ...

batch_proc([], good_cb)  # OK
batch_proc([], bad_cb)   # Error! Argument 2 has incompatible type because of
                         # different name and kind in the callback

Вызываемые объекты, принимающие другие вызываемые объекты в качестве аргументов, могут указывать, что типы их параметров зависят друг от друга, с помощью ParamSpec. Кроме того, если такой вызываемый объект добавляет аргументы к другим вызываемым объектам или удаляет их, можно использовать оператор Concatenate. Соответственно, они записываются в виде Callable[ParamSpecVariable, ReturnType] и Callable[Concatenate[Arg1Type, Arg2Type, ..., ParamSpecVariable], ReturnType].

Изменено в версии 3.10: Callable теперь поддерживает ParamSpec и Concatenate. Подробнее см. в PEP 612.

См. также

В документации по ParamSpec и Concatenate приведены примеры использования в Callable.

Обобщённые типы

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

from collections.abc import Mapping, Sequence

class Employee: ...

# Sequence[Employee] indicates that all elements in the sequence
# must be instances of "Employee".
# Mapping[str, str] indicates that all keys and all values in the mapping
# must be strings.
def notify_by_email(employees: Sequence[Employee],
                    overrides: Mapping[str, str]) -> None: ...

Обобщённые типы можно параметризовать с помощью фабрики TypeVar из typing.

from collections.abc import Sequence
from typing import TypeVar

T = TypeVar('T')                  # Declare type variable "T"

def first(l: Sequence[T]) -> T:   # Function is generic over the TypeVar "T"
    return l[0]

Аннотирование кортежей

Для большинства контейнеров в Python система типизации предполагает, что все элементы контейнера будут иметь один и тот же тип. Например:

from collections.abc import Mapping

# Type checker will infer that all elements in ``x`` are meant to be ints
x: list[int] = []

# Type checker error: ``list`` only accepts a single type argument:
y: list[int, str] = [1, 'foo']

# Type checker will infer that all keys in ``z`` are meant to be strings,
# and that all values in ``z`` are meant to be either strings or ints
z: Mapping[str, str | int] = {}

list принимает только один аргумент типа, поэтому средство проверки типов выдало бы ошибку для приведённого выше присваивания y. Аналогично, Mapping принимает только два аргумента типа: первый задаёт тип ключей, второй — тип значений.

Однако, в отличие от большинства других контейнеров Python, в идиоматичном коде Python часто встречаются кортежи, элементы которых имеют разные типы. Поэтому кортежи обрабатываются в системе типизации Python особым образом. tuple принимает любое число аргументов типа:

# OK: ``x`` is assigned to a tuple of length 1 where the sole element is an int
x: tuple[int] = (5,)

# OK: ``y`` is assigned to a tuple of length 2;
# element 1 is an int, element 2 is a str
y: tuple[int, str] = (5, "foo")

# Error: the type annotation indicates a tuple of length 1,
# but ``z`` has been assigned to a tuple of length 3
z: tuple[int] = (1, 2, 3)

Чтобы обозначить кортеж, который может иметь любую длину и все элементы которого имеют один и тот же тип T, используйте tuple[T, ...]. Чтобы обозначить пустой кортеж, используйте tuple[()]. Использование обычного tuple в качестве аннотации равносильно использованию tuple[Any, ...]:

x: tuple[int, ...] = (1, 2)
# These reassignments are OK: ``tuple[int, ...]`` indicates x can be of any length
x = (1, 2, 3)
x = ()
# This reassignment is an error: all elements in ``x`` must be ints
x = ("foo", "bar")

# ``y`` can only ever be assigned to an empty tuple
y: tuple[()] = ()

z: tuple = ("foo", "bar")
# These reassignments are OK: plain ``tuple`` is equivalent to ``tuple[Any, ...]``
z = (1, 2, 3)
z = ()

Тип объектов классов

Переменная с аннотацией C может принимать значение типа C. Напротив, переменная с аннотацией type[C] (или typing.Type[C]) может принимать значения, которые сами являются классами — в частности, она примет объект класса C. Например:

a = 3         # Has type ``int``
b = int       # Has type ``type[int]``
c = type(a)   # Also has type ``type[int]``

Обратите внимание, что type[C] ковариантен:

class User: ...
class ProUser(User): ...
class TeamUser(User): ...

def make_new_user(user_class: type[User]) -> User:
    # ...
    return user_class()

make_new_user(User)      # OK
make_new_user(ProUser)   # Also OK: ``type[ProUser]`` is a subtype of ``type[User]``
make_new_user(TeamUser)  # Still fine
make_new_user(User())    # Error: expected ``type[User]`` but got ``User``
make_new_user(int)       # Error: ``type[int]`` is not a subtype of ``type[User]``

Для type допустимы только классы, Any, переменные типов и объединения любых таких типов. Например:

def new_non_team_user(user_class: type[BasicUser | ProUser]): ...

new_non_team_user(BasicUser)  # OK
new_non_team_user(ProUser)    # OK
new_non_team_user(TeamUser)   # Error: ``type[TeamUser]`` is not a subtype
                              # of ``type[BasicUser | ProUser]``
new_non_team_user(User)       # Also an error

type[Any] эквивалентно type, который является корнем иерархии метаклассов Python.

Определяемые пользователем обобщённые типы

Определяемый пользователем класс можно объявить обобщённым.

from typing import TypeVar, Generic
from logging import Logger

T = TypeVar('T')

class LoggedVar(Generic[T]):
    def __init__(self, value: T, name: str, logger: Logger) -> None:
        self.name = name
        self.logger = logger
        self.value = value

    def set(self, new: T) -> None:
        self.log('Set ' + repr(self.value))
        self.value = new

    def get(self) -> T:
        self.log('Get ' + repr(self.value))
        return self.value

    def log(self, message: str) -> None:
        self.logger.info('%s: %s', self.name, message)

Использование Generic[T] в качестве базового класса определяет, что класс LoggedVar принимает один параметр типа T . Это также позволяет использовать T в качестве типа внутри тела класса.

Базовый класс Generic определяет __class_getitem__(), благодаря чему LoggedVar[T] можно использовать в качестве типа:

from collections.abc import Iterable

def zero_all_vars(vars: Iterable[LoggedVar[int]]) -> None:
    for var in vars:
        var.set(0)

Обобщённый тип может иметь любое число переменных типов. В качестве параметров обобщённого типа допустимы все разновидности TypeVar:

from typing import TypeVar, Generic, Sequence

T = TypeVar('T', contravariant=True)
B = TypeVar('B', bound=Sequence[bytes], covariant=True)
S = TypeVar('S', int, str)

class WeirdTrio(Generic[T, B, S]):
    ...

Все аргументы-переменные типов для Generic должны быть различными. Поэтому следующий пример недопустим:

from typing import TypeVar, Generic
...

T = TypeVar('T')

class Pair(Generic[T, T]):   # INVALID
    ...

С Generic можно использовать множественное наследование:

from collections.abc import Sized
from typing import TypeVar, Generic

T = TypeVar('T')

class LinkedList(Sized, Generic[T]):
    ...

При наследовании от обобщённых классов некоторые параметры типов можно зафиксировать:

from collections.abc import Mapping
from typing import TypeVar

T = TypeVar('T')

class MyDict(Mapping[str, T]):
    ...

В этом случае MyDict имеет один параметр — T.

Если использовать обобщённый класс, не указывая параметры типов, для каждой позиции предполагается Any. В следующем примере MyIterable не является обобщённым, но неявно наследуется от Iterable[Any]:

from collections.abc import Iterable

class MyIterable(Iterable): # Same as Iterable[Any]
    ...

Также поддерживаются определяемые пользователем псевдонимы обобщённых типов. Примеры:

from collections.abc import Iterable
from typing import TypeVar
S = TypeVar('S')
Response = Iterable[S] | int

# Return type here is same as Iterable[str] | int
def response(query: str) -> Response[str]:
    ...

T = TypeVar('T', int, float, complex)
Vec = Iterable[tuple[T, T]]

def inproduct(v: Vec[T]) -> T: # Same as Iterable[tuple[T, T]]
    return sum(x*y for x, y in v)

Изменено в версии 3.7: У Generic больше нет собственного метакласса.

Определяемые пользователем обобщённые типы для выражений параметров также поддерживаются с помощью переменных спецификации параметров в форме Generic[P]. Их поведение соответствует описанному выше поведению переменных типов, поскольку модуль typing рассматривает переменные спецификации параметров как специализированные переменные типов. Единственное отличие состоит в том, что список типов можно использовать для подстановки вместо ParamSpec:

>>> from typing import Generic, ParamSpec, TypeVar

>>> T = TypeVar('T')
>>> P = ParamSpec('P')

>>> class Z(Generic[T, P]): ...
...
>>> Z[int, [dict, float]]
__main__.Z[int, (<class 'dict'>, <class 'float'>)]

Кроме того, обобщённый тип только с одной переменной спецификации параметров принимает списки параметров в формах X[[Type1, Type2, ...]], а также X[Type1, Type2, ...] — из эстетических соображений. Внутри второй вариант преобразуется в первый, поэтому следующие записи эквивалентны:

>>> class X(Generic[P]): ...
...
>>> X[int, str]
__main__.X[(<class 'int'>, <class 'str'>)]
>>> X[[int, str]]
__main__.X[(<class 'int'>, <class 'str'>)]

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

Изменено в версии 3.10: Generic теперь можно параметризовать выражениями параметров. Подробнее см. в ParamSpec и PEP 612.

Определяемый пользователем обобщённый класс может иметь ABC в качестве базовых классов, не вызывая конфликта метаклассов. Обобщённые метаклассы не поддерживаются. Результат параметризации обобщённых типов кэшируется; большинство типов в модуле typing хешируемы и поддерживают сравнение на равенство.

Тип Any

Особым типом является Any. Средство статической проверки типов считает каждый тип совместимым с Any, а Any — совместимым с каждым типом.

Это означает, что над значением типа Any можно выполнять любые операции и вызывать любые методы, а также присваивать его любой переменной:

from typing import Any

a: Any = None
a = []          # OK
a = 2           # OK

s: str = ''
s = a           # OK

def foo(item: Any) -> int:
    # Passes type checking; 'item' could be any type,
    # and that type might have a 'bar' method
    item.bar()
    ...

Обратите внимание, что при присваивании значения типа Any переменной с более точным типом проверка типов не выполняется. Например, средство статической проверки типов не сообщило об ошибке при присваивании a переменной s, несмотря на то что s объявлена как тип str, а во время выполнения получает значение int!

Кроме того, для всех функций без указанного типа возвращаемого значения или типов параметров неявно используется Any:

def legacy_parser(text):
    ...
    return data

# A static type checker will treat the above
# as having the same signature as:
def legacy_parser(text: Any) -> Any:
    ...
    return data

Такое поведение позволяет использовать Any как запасной выход, когда необходимо сочетать динамически и статически типизированный код.

Сравните поведение Any с поведением object. Как и в случае с Any, каждый тип является подтипом object. Однако, в отличие от Any, обратное неверно: object не является подтипом всех остальных типов.

Это означает, что если тип значения — object, средство проверки типов отклонит почти все операции с ним, а его присваивание переменной (или использование в качестве возвращаемого значения) с более специализированным типом будет ошибкой типов. Например:

def hash_a(item: object) -> int:
    # Fails type checking; an object does not have a 'magic' method.
    item.magic()
    ...

def hash_b(item: Any) -> int:
    # Passes type checking
    item.magic()
    ...

# Passes type checking, since ints and strs are subclasses of object
hash_a(42)
hash_a("foo")

# Passes type checking, since Any is compatible with all types
hash_b(42)
hash_b("foo")

Используйте object, чтобы безопасно указать, что значение может иметь любой тип. Используйте Any, чтобы указать, что значение имеет динамический тип.

Номинальная и структурная подтипизация

Изначально PEP 484 определял систему статической типизации Python как использующую номинальную подтипизацию. Это означает, что класс A допускается там, где ожидается класс B, тогда и только тогда, когда A является подклассом B.

Ранее это требование распространялось и на абстрактные базовые классы, такие как Iterable. Проблема такого подхода в том, что класс нужно было явно помечать как поддерживающий их, что неидиоматично для Python и отличается от обычного подхода в идиоматичном динамически типизированном коде Python. Например, следующий код соответствует PEP 484:

from collections.abc import Sized, Iterable, Iterator

class Bucket(Sized, Iterable[int]):
    ...
    def __len__(self) -> int: ...
    def __iter__(self) -> Iterator[int]: ...

PEP 544 позволяет решить эту проблему: пользователь может написать приведённый выше код без явного указания базовых классов в определении класса, а средство статической проверки типов может неявно считать Bucket подтипом и Sized, и Iterable[int]. Это называется структурной подтипизацией (или статической утиной типизацией):

from collections.abc import Iterator, Iterable

class Bucket:  # Note: no base classes
    ...
    def __len__(self) -> int: ...
    def __iter__(self) -> Iterator[int]: ...

def collect(items: Iterable[int]) -> int: ...
result = collect(Bucket())  # Passes type check

Кроме того, наследуясь от специального класса Protocol, пользователь может определить собственные протоколы и в полной мере использовать структурную подтипизацию (см. примеры ниже).

Содержимое модуля

Модуль typing определяет следующие классы, функции и декораторы.

Специальные примитивы типизации

Специальные типы

Их можно использовать в качестве типов в аннотациях. Они не поддерживают индексацию с помощью [].

typing.Any

Специальный тип, обозначающий неограниченный тип.

  • Каждый тип совместим с Any.
  • Any совместим с каждым типом.

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

typing.AnyStr

Ограниченная переменная типа.

Определение:

AnyStr = TypeVar('AnyStr', str, bytes)

AnyStr предназначен для функций, принимающих аргументы типа str или bytes, но не допускающих их смешивания.

Например:

def concat(a: AnyStr, b: AnyStr) -> AnyStr:
    return a + b

concat("foo", "bar")    # OK, output has type 'str'
concat(b"foo", b"bar")  # OK, output has type 'bytes'
concat("foo", b"bar")   # Error, cannot mix str and bytes

Обратите внимание: несмотря на название, AnyStr никак не связан с типом Any и не означает «любая строка». В частности, AnyStr и str | bytes — это разные типы с разными сценариями использования:

# Invalid use of AnyStr:
# The type variable is used only once in the function signature,
# so cannot be "solved" by the type checker
def greet_bad(cond: bool) -> AnyStr:
    return "hi there!" if cond else b"greetings!"

# The better way of annotating this function:
def greet_proper(cond: bool) -> str | bytes:
    return "hi there!" if cond else b"greetings!"
typing.LiteralString

Специальный тип, включающий только строковые литералы.

Любой строковый литерал совместим с LiteralString, как и другой LiteralString. Однако объект, тип которого указан просто как str, несовместим с ним. Строка, созданная объединением объектов типа LiteralString, также допустима в качестве LiteralString.

Пример:

def run_query(sql: LiteralString) -> None:
    ...

def caller(arbitrary_string: str, literal_string: LiteralString) -> None:
    run_query("SELECT * FROM students")  # OK
    run_query(literal_string)  # OK
    run_query("SELECT * FROM " + literal_string)  # OK
    run_query(arbitrary_string)  # type checker error
    run_query(  # type checker error
        f"SELECT * FROM students WHERE name = {arbitrary_string}"
    )

LiteralString полезен для чувствительных API, в которых произвольные строки, созданные пользователями, могут приводить к проблемам. Например, два приведённых выше случая, вызывающие ошибки средства проверки типов, могут быть уязвимы для SQL-инъекций.

Подробнее см. PEP 675.

Добавлено в версии 3.11.

typing.Never

Нижний тип — тип, не имеющий элементов.

Его можно использовать для определения функции, которую нельзя вызывать, или функции, которая никогда не возвращает управление:

from typing import Never

def never_call_me(arg: Never) -> None:
    pass

def int_or_str(arg: int | str) -> None:
    never_call_me(arg)  # type checker error
    match arg:
        case int():
            print("It's an int")
        case str():
            print("It's a str")
        case _:
            never_call_me(arg)  # OK, arg is of type Never

Добавлено в версии 3.11: В более старых версиях Python для выражения того же понятия можно использовать NoReturn. Тип Never добавлен, чтобы яснее обозначить предполагаемый смысл.

typing.NoReturn

Специальный тип, обозначающий, что функция никогда не возвращает управление.

Например:

from typing import NoReturn

def stop() -> NoReturn:
    raise RuntimeError('no way')

NoReturn также можно использовать в качестве нижнего типа — типа, не имеющего значений. Начиная с Python 3.11 для этого понятия следует использовать тип Never. Средства проверки типов должны считать эти типы эквивалентными.

Добавлено в версии 3.6.2.

typing.Self

Специальный тип для представления текущего охватывающего класса.

Например:

from typing import Self, reveal_type

class Foo:
    def return_self(self) -> Self:
        ...
        return self

class SubclassOfFoo(Foo): pass

reveal_type(Foo().return_self())  # Revealed type is "Foo"
reveal_type(SubclassOfFoo().return_self())  # Revealed type is "SubclassOfFoo"

Семантически эта аннотация эквивалентна следующей, но записывается короче:

from typing import TypeVar

Self = TypeVar("Self", bound="Foo")

class Foo:
    def return_self(self: Self) -> Self:
        ...
        return self

Как правило, если что-либо возвращает self, как в примерах выше, следует использовать Self в качестве аннотации возвращаемого типа. Если бы Foo.return_self был аннотирован как возвращающий "Foo", средство проверки типов определило бы тип объекта, возвращаемого SubclassOfFoo.return_self, как Foo, а не SubclassOfFoo.

Другие распространённые сценарии использования:

  • classmethod, используемые как альтернативные конструкторы и возвращающие экземпляры параметра cls.
  • Аннотирование метода __enter__(), который возвращает self.

Не следует использовать Self в качестве аннотации возвращаемого типа, если при наследовании от класса метод не гарантирует возврат экземпляра подкласса:

class Eggs:
    # Self would be an incorrect return annotation here,
    # as the object returned is always an instance of Eggs,
    # even in subclasses
    def returns_eggs(self) -> "Eggs":
        return Eggs()

Подробнее см. PEP 673.

Добавлено в версии 3.11.

typing.TypeAlias

Специальная аннотация для явного объявления псевдонима типа.

Например:

from typing import TypeAlias

Factors: TypeAlias = list[int]

TypeAlias особенно полезен для аннотирования псевдонимов, использующих отложенные ссылки, поскольку средствам проверки типов может быть сложно отличить их от обычных присваиваний переменным:

from typing import Generic, TypeAlias, TypeVar

T = TypeVar("T")

# "Box" does not exist yet,
# so we have to use quotes for the forward reference.
# Using ``TypeAlias`` tells the type checker that this is a type alias declaration,
# not a variable assignment to a string.
BoxOfStrings: TypeAlias = "Box[str]"

class Box(Generic[T]):
    @classmethod
    def make_box_of_strings(cls) -> BoxOfStrings: ...

Подробнее см. PEP 613.

Добавлено в версии 3.10.

Специальные формы

Их можно использовать в качестве типов в аннотациях. Все они поддерживают индексацию с помощью [], но у каждой свой синтаксис.

typing.Union

Объединённый тип; Union[X, Y] эквивалентно X | Y и означает «X или Y».

Чтобы определить объединение, используйте, например, Union[int, str] или сокращённую форму int | str. Рекомендуется использовать сокращённую форму. Подробнее:

  • Аргументы должны быть типами, и хотя бы один аргумент должен быть указан.
  • Вложенные объединения уплощаются, например:

    Union[Union[int, str], float] == Union[int, str, float]
    
  • Объединения с одним аргументом исчезают, например:

    Union[int] == int  # The constructor actually returns int
    
  • Повторяющиеся аргументы пропускаются, например:

    Union[int, str, int] == Union[int, str] == int | str
    
  • При сравнении объединений порядок аргументов не учитывается, например:

    Union[int, str] == Union[str, int]
    
  • Нельзя создавать подклассы Union или экземпляры этого типа.
  • Нельзя записывать Union[X][Y].

Изменено в версии 3.7: Не удаляйте явные подклассы из объединений во время выполнения.

Изменено в версии 3.10: Объединения теперь можно записывать как X | Y. См. выражения объединённых типов.

typing.Optional

Optional[X] эквивалентно X | None (или Union[X, None]).

Обратите внимание, что это не то же самое, что необязательный аргумент, то есть аргумент со значением по умолчанию. Для необязательного аргумента со значением по умолчанию не требуется указывать квалификатор Optional в аннотации типа только потому, что аргумент необязателен. Например:

def foo(arg: int = 0) -> None:
    ...

С другой стороны, если допускается явное значение None, использование Optional уместно независимо от того, является ли аргумент необязательным. Например:

def foo(arg: Optional[int] = None) -> None:
    ...

Изменено в версии 3.10: Optional теперь можно записывать как X | None. См. выражения объединённых типов.

typing.Concatenate

Специальная форма для аннотирования функций высшего порядка.

Concatenate можно использовать вместе с Callable и ParamSpec для аннотирования вызываемого объекта высшего порядка, который добавляет, удаляет или преобразует параметры другого вызываемого объекта. Используется в форме Concatenate[Arg1Type, Arg2Type, ..., ParamSpecVariable]. В настоящее время Concatenate допустим только в качестве первого аргумента Callable. Последний параметр Concatenate должен быть объектом ParamSpec или многоточием (...).

Например, чтобы аннотировать декоратор with_lock, передающий threading.Lock декорируемой функции, можно использовать Concatenate, чтобы указать, что with_lock ожидает вызываемый объект, принимающий Lock в качестве первого аргумента, и возвращает вызываемый объект с другой сигнатурой типа. В этом случае ParamSpec указывает, что типы параметров возвращаемого вызываемого объекта зависят от типов параметров переданного вызываемого объекта:

from collections.abc import Callable
from threading import Lock
from typing import Concatenate, ParamSpec, TypeVar

P = ParamSpec('P')
R = TypeVar('R')

# Use this lock to ensure that only one thread is executing a function
# at any time.
my_lock = Lock()

def with_lock(f: Callable[Concatenate[Lock, P], R]) -> Callable[P, R]:
    '''A type-safe decorator which provides a lock.'''
    def inner(*args: P.args, **kwargs: P.kwargs) -> R:
        # Provide the lock as the first argument.
        return f(my_lock, *args, **kwargs)
    return inner

@with_lock
def sum_threadsafe(lock: Lock, numbers: list[float]) -> float:
    '''Add a list of numbers together in a thread-safe manner.'''
    with lock:
        return sum(numbers)

# We don't need to pass in the lock ourselves thanks to the decorator.
sum_threadsafe([1.1, 2.2, 3.3])

Добавлено в версии 3.10.

См. также

  • PEP 612 — переменные спецификации параметров (PEP, в котором представлены ParamSpec и Concatenate)
  • ParamSpec
  • Аннотирование вызываемых объектов
typing.Literal

Специальная форма типизации для определения «литеральных типов».

Literal можно использовать, чтобы сообщить средствам проверки типов, что значение аннотированного объекта эквивалентно одному из указанных литералов.

Например:

def validate_simple(data: Any) -> Literal[True]:  # always returns True
    ...

Mode: TypeAlias = Literal['r', 'rb', 'w', 'wb']
def open_helper(file: str, mode: Mode) -> str:
    ...

open_helper('/some/path', 'r')      # Passes type check
open_helper('/other/path', 'typo')  # Error in type checker

От Literal[...] нельзя создавать подклассы. Во время выполнения в качестве аргумента типа для Literal[...] допускается произвольное значение, однако средства проверки типов могут накладывать ограничения. Подробнее о литеральных типах см. PEP 586.

Добавлено в версии 3.8.

Изменено в версии 3.9.1: Literal теперь удаляет повторяющиеся параметры. Сравнение объектов Literal на равенство больше не зависит от порядка. Если один из параметров объектов Literal не является хешируемым, при сравнении на равенство теперь будет вызвано исключение TypeError.

typing.ClassVar

Специальная конструкция типа для обозначения переменных класса.

Как указано в PEP 526, аннотация переменной, обёрнутая в ClassVar, указывает, что атрибут предназначен для использования в качестве переменной класса и не должен задаваться в экземплярах этого класса. Использование:

class Starship:
    stats: ClassVar[dict[str, int]] = {} # class variable
    damage: int = 10                     # instance variable

ClassVar принимает только типы и не может индексироваться дальше.

ClassVar сам по себе не является классом, поэтому его не следует использовать с isinstance() или issubclass(). ClassVar не меняет поведение Python во время выполнения, но может использоваться сторонними средствами проверки типов. Например, средство проверки типов может пометить следующий код как ошибочный:

enterprise_d = Starship(3000)
enterprise_d.stats = {} # Error, setting class variable on instance
Starship.stats = {}     # This is OK

Добавлено в версии 3.5.3.

typing.Final

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

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

Например:

MAX_SIZE: Final = 9000
MAX_SIZE += 1  # Error reported by type checker

class Connection:
    TIMEOUT: Final[int] = 10

class FastConnector(Connection):
    TIMEOUT = 1  # Error reported by type checker

Во время выполнения проверка этих свойств не выполняется. Подробнее см. PEP 591.

Добавлено в версии 3.8.

typing.Required

Специальная конструкция типизации для обозначения обязательного ключа в TypedDict.

В основном она полезна для total=False TypedDict. Подробнее см. TypedDict и PEP 655.

Добавлено в версии 3.11.

typing.NotRequired

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

Подробнее см. TypedDict и PEP 655.

Добавлено в версии 3.11.

typing.Annotated

Специальная форма типизации для добавления к аннотации контекстно-зависимых метаданных.

Добавьте метаданные x к заданному типу T с помощью аннотации Annotated[T, x]. Метаданные, добавленные с помощью Annotated, могут использоваться средствами статического анализа или во время выполнения. Во время выполнения метаданные сохраняются в атрибуте __metadata__.

Если библиотека или инструмент встречает аннотацию Annotated[T, x] и не имеет специальной логики для работы с метаданными, он должен игнорировать метаданные и просто считать аннотацию типом T. Таким образом, Annotated может быть полезен в коде, использующем аннотации для целей, не связанных с системой статической типизации Python.

Использование Annotated[T, x] в качестве аннотации по-прежнему позволяет выполнять статическую проверку типов для T, поскольку средства проверки типов просто игнорируют метаданные x. В этом отношении Annotated отличается от декоратора @no_type_check, который также можно использовать для добавления аннотаций за пределами системы типизации, но который полностью отключает проверку типов для функции или класса.

Интерпретация метаданных зависит от инструмента или библиотеки, встретивших аннотацию Annotated. Инструмент или библиотека, встретившие тип Annotated, могут просмотреть элементы метаданных и определить, представляют ли они интерес (например, с помощью isinstance()).

Annotated[<type>, <metadata>]

Вот пример того, как можно использовать Annotated для добавления метаданных к аннотациям типов при анализе диапазонов:

@dataclass
class ValueRange:
    lo: int
    hi: int

T1 = Annotated[int, ValueRange(-10, 5)]
T2 = Annotated[T1, ValueRange(-20, 3)]

Подробности синтаксиса:

  • Первый аргумент Annotated должен быть допустимым типом
  • Можно указать несколько элементов метаданных (Annotated поддерживает переменное число аргументов):

    @dataclass
    class ctype:
        kind: str
    
    Annotated[int, ValueRange(3, 10), ctype("char")]
    

    Инструмент, обрабатывающий аннотации, сам определяет, разрешено ли клиенту добавлять несколько элементов метаданных к одной аннотации и как объединять эти аннотации.

  • Annotated необходимо индексировать как минимум с двумя аргументами ( Annotated[int] недопустимо)
  • Порядок элементов метаданных сохраняется и учитывается при проверке на равенство:

    assert Annotated[int, ValueRange(3, 10), ctype("char")] != Annotated[
        int, ctype("char"), ValueRange(3, 10)
    ]
    
  • Вложенные типы Annotated уплощаются. Порядок элементов метаданных начинается с самой внутренней аннотации:

    assert Annotated[Annotated[int, ValueRange(3, 10)], ctype("char")] == Annotated[
        int, ValueRange(3, 10), ctype("char")
    ]
    
  • Повторяющиеся элементы метаданных не удаляются:

    assert Annotated[int, ValueRange(3, 10)] != Annotated[
        int, ValueRange(3, 10), ValueRange(3, 10)
    ]
    
  • Annotated можно использовать с вложенными и обобщёнными псевдонимами:

    @dataclass
    class MaxLen:
        value: int
    
    T = TypeVar("T")
    Vec: TypeAlias = Annotated[list[tuple[T, T]], MaxLen(10)]
    
    assert Vec[int] == Annotated[list[tuple[int, int]], MaxLen(10)]
    
  • Annotated нельзя использовать с распакованным TypeVarTuple:

    Variadic: TypeAlias = Annotated[*Ts, Ann1]  # NOT valid
    

    Это было бы эквивалентно следующему:

    Annotated[T1, T2, T3, ..., Ann1]
    

    где T1, T2 и т. д. — это TypeVars. Такой вариант недопустим: в Annotated следует передавать только один тип.

  • По умолчанию get_type_hints() удаляет метаданные из аннотаций. Передайте include_extras=True, чтобы сохранить метаданные:

    >>> from typing import Annotated, get_type_hints
    >>> def func(x: Annotated[int, "metadata"]) -> None: pass
    ...
    >>> get_type_hints(func)
    {'x': <class 'int'>, 'return': <class 'NoneType'>}
    >>> get_type_hints(func, include_extras=True)
    {'x': typing.Annotated[int, 'metadata'], 'return': <class 'NoneType'>}
    
  • Во время выполнения связанные с типом Annotated метаданные можно получить через атрибут __metadata__:

    >>> from typing import Annotated
    >>> X = Annotated[int, "very", "important", "metadata"]
    >>> X
    typing.Annotated[int, 'very', 'important', 'metadata']
    >>> X.__metadata__
    ('very', 'important', 'metadata')
    

См. также

PEP 593 — гибкие аннотации функций и переменных

PEP, добавляющий Annotated в стандартную библиотеку.

Добавлено в версии 3.9.

typing.TypeGuard

Специальная конструкция типизации для пометки пользовательских функций проверки типа.

TypeGuard можно использовать для аннотирования возвращаемого типа пользовательской функции проверки типа. TypeGuard принимает только один аргумент типа. Во время выполнения такие функции должны возвращать логическое значение.

Назначение TypeGuard — поддержка сужения типа: метода, используемого средствами статической проверки типов для определения более точного типа выражения в ходе выполнения кода программы. Обычно сужение типа выполняется путём анализа условного потока выполнения и применения сужения к блоку кода. Условное выражение в данном случае иногда называют «проверкой типа»:

def is_str(val: str | float):
    # "isinstance" type guard
    if isinstance(val, str):
        # Type of ``val`` is narrowed to ``str``
        ...
    else:
        # Else, type of ``val`` is narrowed to ``float``.
        ...

Иногда было бы удобно использовать пользовательскую логическую функцию для проверки типа. Такая функция должна указывать TypeGuard[...] в качестве возвращаемого типа, чтобы сообщить о таком намерении средствам статической проверки типов.

Использование -> TypeGuard сообщает средству статической проверки типов следующее:

  1. Возвращаемое значение является логическим.
  2. Если возвращаемое значение равно True, тип аргумента совпадает с типом внутри TypeGuard.

Например:

def is_str_list(val: list[object]) -> TypeGuard[list[str]]:
    '''Determines whether all objects in the list are strings'''
    return all(isinstance(x, str) for x in val)

def func1(val: list[object]):
    if is_str_list(val):
        # Type of ``val`` is narrowed to ``list[str]``.
        print(" ".join(val))
    else:
        # Type of ``val`` remains as ``list[object]``.
        print("Not a list of strings!")

Если is_str_list — метод класса или экземпляра, то тип в TypeGuard соответствует типу второго параметра после cls или self.

Кратко говоря, форма def foo(arg: TypeA) -> TypeGuard[TypeB]: ... означает, что если foo(arg) возвращает True, то arg сужается с TypeA до TypeB.

Примечание

TypeB не обязательно должен быть более узким типом, чем TypeA; он может быть даже более широким. Это сделано главным образом для случаев вроде сужения list[object] до list[str], несмотря на то что последний не является подтипом первого, поскольку list инвариантен. Ответственность за написание безопасных с точки зрения типов проверок типа лежит на пользователе.

TypeGuard также работает с переменными типа. Подробнее см. PEP 647.

Добавлено в версии 3.10.

typing.Unpack

Оператор типизации, концептуально обозначающий распаковку объекта.

Например, использование оператора распаковки * для кортежа переменных типа эквивалентно использованию Unpack для обозначения распакованного кортежа переменных типа:

Ts = TypeVarTuple('Ts')
tup: tuple[*Ts]
# Effectively does:
tup: tuple[Unpack[Ts]]

Фактически, Unpack можно взаимозаменяемо использовать с * для типов typing.TypeVarTuple и builtins.tuple. В более старых версиях Python можно встретить явное использование Unpack, где * нельзя было использовать в некоторых местах:

# In older versions of Python, TypeVarTuple and Unpack
# are located in the `typing_extensions` backports package.
from typing_extensions import TypeVarTuple, Unpack

Ts = TypeVarTuple('Ts')
tup: tuple[*Ts]         # Syntax error on Python <= 3.10!
tup: tuple[Unpack[Ts]]  # Semantically equivalent, and backwards-compatible

Добавлено в версии 3.11.

Создание обобщённых типов

Следующие классы не следует использовать непосредственно в качестве аннотаций. Их назначение — служить строительными блоками для создания обобщённых типов.

class typing.Generic

Абстрактный базовый класс для обобщённых типов.

Обобщённый тип обычно объявляется наследованием от экземпляра этого класса с одной или несколькими переменными типа. Например, обобщённый тип отображения можно определить следующим образом:

class Mapping(Generic[KT, VT]):
    def __getitem__(self, key: KT) -> VT:
        ...
        # Etc.

Затем этот класс можно использовать следующим образом:

X = TypeVar('X')
Y = TypeVar('Y')

def lookup_name(mapping: Mapping[X, Y], key: X, default: Y) -> Y:
    try:
        return mapping[key]
    except KeyError:
        return default
class typing.TypeVar(name, *constraints, bound=None, covariant=False, contravariant=False)

Переменная типа.

Использование:

T = TypeVar('T')  # Can be anything
S = TypeVar('S', bound=str)  # Can be any subtype of str
A = TypeVar('A', str, bytes)  # Must be exactly str or bytes

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

def repeat(x: T, n: int) -> Sequence[T]:
    """Return a list containing n references to x."""
    return [x]*n


def print_capitalized(x: S) -> S:
    """Print x capitalized, and return x."""
    print(x.capitalize())
    return x


def concatenate(x: A, y: A) -> A:
    """Add two strings or bytes objects together."""
    return x + y

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

Переменные типа можно пометить как ковариантные или контравариантные, передав covariant=True или contravariant=True. Дополнительные сведения см. в PEP 484. По умолчанию переменные типа инвариантны.

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

x = print_capitalized('a string')
reveal_type(x)  # revealed type is str

class StringSubclass(str):
    pass

y = print_capitalized(StringSubclass('another string'))
reveal_type(y)  # revealed type is StringSubclass

z = print_capitalized(45)  # error: int is not a subtype of str

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

U = TypeVar('U', bound=str|bytes)  # Can be any subtype of the union str|bytes
V = TypeVar('V', bound=SupportsAbs)  # Can be anything with an __abs__ method

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

a = concatenate('one', 'two')
reveal_type(a)  # revealed type is str

b = concatenate(StringSubclass('one'), StringSubclass('two'))
reveal_type(b)  # revealed type is str, despite StringSubclass being passed in

c = concatenate('one', b'two')  # error: type variable 'A' can be either str or bytes in a function call, but not both

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

__name__

Имя переменной типа.

__covariant__

Указывает, помечена ли переменная типа как ковариантная.

__contravariant__

Указывает, помечена ли переменная типа как контравариантная.

__bound__

Ограничение переменной типа, если оно задано.

__constraints__

Кортеж, содержащий ограничения переменной типа, если они заданы.

class typing.TypeVarTuple(name)

Кортеж переменных типа. Специализированная форма переменной типа, позволяющая создавать вариативные обобщённые типы.

Использование:

T = TypeVar("T")
Ts = TypeVarTuple("Ts")

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

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

# T is bound to int, Ts is bound to ()
# Return value is (1,), which has type tuple[int]
move_first_element_to_last(tup=(1,))

# T is bound to int, Ts is bound to (str,)
# Return value is ('spam', 1), which has type tuple[str, int]
move_first_element_to_last(tup=(1, 'spam'))

# T is bound to int, Ts is bound to (str, float)
# Return value is ('spam', 3.0, 1), which has type tuple[str, float, int]
move_first_element_to_last(tup=(1, 'spam', 3.0))

# This fails to type check (and fails at runtime)
# because tuple[()] is not compatible with tuple[T, *Ts]
# (at least one element is required)
move_first_element_to_last(tup=())

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

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

x: Ts          # Not valid
x: tuple[Ts]   # Not valid
x: tuple[*Ts]  # The correct way to do it

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

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')
Shape = TypeVarTuple('Shape')

class Array(Generic[DType, *Shape]):  # This is fine
    pass

class Array2(Generic[*Shape, DType]):  # This would also be fine
    pass

class Height: ...
class Width: ...

float_array_1d: Array[float, Height] = Array()     # Totally fine
int_array_2d: Array[int, Height, Width] = Array()  # Yup, fine too

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

x: tuple[*Ts, *Ts]                     # Not valid
class Array(Generic[*Shape, *Shape]):  # Not valid
    pass

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

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

В отличие от нераспакованных аннотаций для *args — например, *args: int, которая указывала бы, что все аргументы имеют тип int, — *args: *Ts позволяет ссылаться на типы отдельных аргументов в *args. Здесь это позволяет убедиться, что типы *args, передаваемых в call_soon, соответствуют типам позиционных аргументов callback.

Дополнительные сведения о кортежах переменных типа см. в PEP 646.

__name__

Имя кортежа переменных типа.

Добавлено в версии 3.11.

class typing.ParamSpec(name, *, bound=None, covariant=False, contravariant=False)

Переменная спецификации параметров. Специализированная версия переменных типа.

Использование:

P = ParamSpec('P')

Переменные спецификации параметров существуют главным образом для статических средств проверки типов. Они используются для передачи типов параметров одной вызываемой сущности другой — шаблон, часто встречающийся в функциях высшего порядка и декораторах. Они допустимы только при использовании в Concatenate, в качестве первого аргумента Callable или в качестве параметров определённых пользователем обобщённых типов. Дополнительные сведения об обобщённых типах см. в Generic.

Например, чтобы добавить базовое журналирование функции, можно создать декоратор add_logging, который записывает вызовы функции в журнал. Переменная спецификации параметров сообщает средству проверки типов, что типовые параметры вызываемой сущности, переданной декоратору, и новой вызываемой сущности, возвращённой им, взаимозависимы:

from collections.abc import Callable
from typing import TypeVar, ParamSpec
import logging

T = TypeVar('T')
P = ParamSpec('P')

def add_logging(f: Callable[P, T]) -> Callable[P, T]:
    '''A type-safe decorator to add logging to a function.'''
    def inner(*args: P.args, **kwargs: P.kwargs) -> T:
        logging.info(f'{f.__name__} was called')
        return f(*args, **kwargs)
    return inner

@add_logging
def add_two(x: float, y: float) -> float:
    '''Add two numbers together.'''
    return x + y

До появления ParamSpec простейшим способом аннотировать это было использование TypeVar с ограничением Callable[..., Any]. Однако это приводит к двум проблемам:

  1. Средство проверки типов не может проверить типы функции inner, поскольку *args и **kwargs должны иметь тип Any.
  2. В теле декоратора add_logging при возврате функции inner может потребоваться cast(); в противном случае статическому средству проверки типов нужно указать игнорировать return inner.
args
kwargs

Поскольку ParamSpec охватывает позиционные и именованные параметры, P.args и P.kwargs можно использовать, чтобы разделить ParamSpec на составляющие. P.args представляет кортеж позиционных параметров заданного вызова и должен использоваться только для аннотирования *args. P.kwargs представляет отображение именованных параметров в их значения в заданном вызове и должен использоваться только для аннотирования **kwargs. Для обоих атрибутов требуется, чтобы аннотируемый параметр находился в области видимости. Во время выполнения P.args и P.kwargs являются экземплярами соответственно ParamSpecArgs и ParamSpecKwargs.

__name__

Имя спецификации параметров.

Переменные спецификации параметров, созданные с помощью covariant=True или contravariant=True, можно использовать для объявления ковариантных или контравариантных обобщённых типов. Также принимается аргумент bound, как и в случае с TypeVar. Однако фактическая семантика этих ключевых слов ещё не определена.

Добавлено в версии 3.10.

Примечание

Сериализовать с помощью pickle можно только переменные спецификации параметров, определённые в глобальной области видимости.

См. также

  • PEP 612 — переменные спецификации параметров (PEP, в котором представлены ParamSpec и Concatenate)
  • Concatenate
  • Аннотирование вызываемых объектов
typing.ParamSpecArgs
typing.ParamSpecKwargs

Атрибуты позиционных и именованных аргументов объекта ParamSpec. Атрибут P.args объекта ParamSpec является экземпляром ParamSpecArgs, а P.kwargs — экземпляром ParamSpecKwargs. Они предназначены для интроспекции во время выполнения и не имеют специального значения для статических средств проверки типов.

Вызов get_origin() для любого из этих объектов вернёт исходный ParamSpec:

>>> from typing import ParamSpec, get_origin
>>> P = ParamSpec("P")
>>> get_origin(P.args) is P
True
>>> get_origin(P.kwargs) is P
True

Добавлено в версии 3.10.

Другие специальные директивы

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

class typing.NamedTuple

Типизированная версия collections.namedtuple().

Использование:

class Employee(NamedTuple):
    name: str
    id: int

Это эквивалентно следующему:

Employee = collections.namedtuple('Employee', ['name', 'id'])

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

class Employee(NamedTuple):
    name: str
    id: int = 3

employee = Employee('Guido')
assert employee.id == 3

Поля со значениями по умолчанию должны следовать за всеми полями без значений по умолчанию.

У созданного класса есть дополнительный атрибут __annotations__, содержащий словарь, который сопоставляет имена полей с типами полей. (Имена полей находятся в атрибуте _fields, а значения по умолчанию — в атрибуте _field_defaults; оба атрибута являются частью API namedtuple().)

У подклассов NamedTuple также могут быть строки документации и методы:

class Employee(NamedTuple):
    """Represents an employee."""
    name: str
    id: int = 3

    def __repr__(self) -> str:
        return f'<Employee {self.name}, id={self.id}>'

Подклассы NamedTuple могут быть обобщёнными:

class Group(NamedTuple, Generic[T]):
    key: T
    group: list[T]

Обратная совместимость использования:

Employee = NamedTuple('Employee', [('name', str), ('id', int)])

Изменено в версии 3.6: Добавлена поддержка синтаксиса аннотаций переменных из PEP 526.

Изменено в версии 3.6.1: Добавлена поддержка значений по умолчанию, методов и строк документации.

Изменено в версии 3.8: Атрибуты _field_types и __annotations__ теперь являются обычными словарями, а не экземплярами OrderedDict.

Изменено в версии 3.9: Атрибут _field_types удалён в пользу более стандартного атрибута __annotations__, содержащего ту же информацию.

Изменено в версии 3.11: Добавлена поддержка обобщённых именованных кортежей.

class typing.NewType(name, tp)

Вспомогательный класс для создания различных типов с низкими накладными расходами.

Средство проверки типов считает NewType отдельным типом. Однако во время выполнения вызов NewType возвращает свой аргумент без изменений.

Использование:

UserId = NewType('UserId', int)  # Declare the NewType "UserId"
first_user = UserId(1)  # "UserId" returns the argument unchanged at runtime
__module__

Модуль, в котором определён новый тип.

__name__

Имя нового типа.

__supertype__

Тип, на основе которого создан новый тип.

Добавлено в версии 3.5.2.

Изменено в версии 3.10: NewType теперь является классом, а не функцией.

class typing.Protocol(Generic)

Базовый класс для классов-протоколов.

Классы-протоколы определяются следующим образом:

class Proto(Protocol):
    def meth(self) -> int:
        ...

Такие классы используются главным образом со статическими средствами проверки типов, распознающими структурную подтипизацию (статическую типизацию по утиной типизации), например:

class C:
    def meth(self) -> int:
        return 0

def func(x: Proto) -> int:
    return x.meth()

func(C())  # Passes static type check

Дополнительные сведения см. в PEP 544. Классы-протоколы, декорированные с помощью runtime_checkable() (описанной далее), выступают в роли упрощённых протоколов времени выполнения, которые проверяют только наличие заданных атрибутов, не учитывая их сигнатуры и типы.

Классы-протоколы могут быть обобщёнными, например:

T = TypeVar("T")

class GenProto(Protocol[T]):
    def meth(self) -> T:
        ...

Добавлено в версии 3.8.

@typing.runtime_checkable

Помечает класс-протокол как протокол времени выполнения.

Такой протокол можно использовать с isinstance() и issubclass(). При применении к классу, не являющемуся протоколом, возникает исключение TypeError. Это позволяет выполнять упрощённую структурную проверку, очень похожую на «пони с одним трюком» в collections.abc, например Iterable. Например:

@runtime_checkable
class Closable(Protocol):
    def close(self): ...

assert isinstance(open('/some/file'), Closable)

@runtime_checkable
class Named(Protocol):
    name: str

import threading
assert isinstance(threading.Thread(name='Bob'), Named)

Примечание

runtime_checkable() проверяет только наличие необходимых методов или атрибутов, но не их сигнатуры или типы. Например, ssl.SSLObject является классом, поэтому он проходит проверку issubclass() относительно Callable. Однако метод ssl.SSLObject.__init__ существует только для вызова исключения TypeError с более информативным сообщением, поэтому вызвать (создать экземпляр) ssl.SSLObject невозможно.

Примечание

Проверка isinstance() для протокола, проверяемого во время выполнения, может оказаться неожиданно медленной по сравнению с проверкой isinstance() для класса, не являющегося протоколом. В коде, критичном к производительности, для структурных проверок рассмотрите альтернативные способы, например вызовы hasattr().

Добавлено в версии 3.8.

class typing.TypedDict(dict)

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

TypedDict объявляет тип словаря, экземпляры которого должны содержать определённый набор ключей, причём каждому ключу соответствует значение согласованного типа. Это требование не проверяется во время выполнения и контролируется только средствами проверки типов. Использование:

class Point2D(TypedDict):
    x: int
    y: int
    label: str

a: Point2D = {'x': 1, 'y': 2, 'label': 'good'}  # OK
b: Point2D = {'z': 3, 'label': 'bad'}           # Fails type check

assert Point2D(x=1, y=2, label='first') == dict(x=1, y=2, label='first')

Чтобы использовать эту возможность в более ранних версиях Python, не поддерживающих PEP 526, TypedDict поддерживает две дополнительные эквивалентные синтаксические формы:

  • Литерал dict в качестве второго аргумента:

    Point2D = TypedDict('Point2D', {'x': int, 'y': int, 'label': str})
    
  • Именованные аргументы:

    Point2D = TypedDict('Point2D', x=int, y=int, label=str)
    

Устарело с версии 3.11, будет удалено в версии 3.13: Синтаксис с именованными аргументами устарел в версии 3.11 и будет удалён в версии 3.13. Он также может не поддерживаться статическими средствами проверки типов.

Функциональный синтаксис также следует использовать, если какие-либо ключи не являются допустимыми идентификаторами, например являются ключевыми словами или содержат дефисы. Пример:

# raises SyntaxError
class Point2D(TypedDict):
    in: int  # 'in' is a keyword
    x-y: int  # name with hyphens

# OK, functional syntax
Point2D = TypedDict('Point2D', {'in': int, 'x-y': int})

По умолчанию все ключи должны присутствовать в TypedDict. Отдельные ключи можно пометить как необязательные с помощью NotRequired:

class Point2D(TypedDict):
    x: int
    y: int
    label: NotRequired[str]

# Alternative syntax
Point2D = TypedDict('Point2D', {'x': int, 'y': int, 'label': NotRequired[str]})

Это означает, что в Point2D TypedDict ключ label можно не указывать.

Также можно по умолчанию сделать необязательными все ключи, указав значение False:

class Point2D(TypedDict, total=False):
    x: int
    y: int

# Alternative syntax
Point2D = TypedDict('Point2D', {'x': int, 'y': int}, total=False)

Это означает, что в Point2D TypedDict можно не указывать любые ключи. Средство проверки типов должно поддерживать в качестве значения аргумента total только литерал False или True. Значение True используется по умолчанию и делает обязательными все элементы, определённые в теле класса.

Отдельные ключи TypedDict типа total=False можно пометить как обязательные с помощью Required:

class Point2D(TypedDict, total=False):
    x: Required[int]
    y: Required[int]
    label: str

# Alternative syntax
Point2D = TypedDict('Point2D', {
    'x': Required[int],
    'y': Required[int],
    'label': str
}, total=False)

Тип TypedDict может наследоваться от одного или нескольких других типов TypedDict с использованием синтаксиса на основе классов. Использование:

class Point3D(Point2D):
    z: int

Point3D содержит три элемента: x, y и z. Это эквивалентно следующему определению:

class Point3D(TypedDict):
    x: int
    y: int
    z: int

TypedDict не может наследоваться от класса, не являющегося TypedDict, за исключением Generic. Например:

class X(TypedDict):
    x: int

class Y(TypedDict):
    y: int

class Z(object): pass  # A non-TypedDict class

class XY(X, Y): pass  # OK

class XZ(X, Z): pass  # raises TypeError

TypedDict может быть обобщённым:

T = TypeVar("T")

class Group(TypedDict, Generic[T]):
    key: T
    group: list[T]

TypedDict можно исследовать с помощью словарей аннотаций (дополнительные сведения о рекомендуемых методах работы с аннотациями см. в разделе Рекомендации по работе с аннотациями), а также атрибутов __total__, __required_keys__ и __optional_keys__.

__total__

Point2D.__total__ содержит значение аргумента total. Пример:

>>> from typing import TypedDict
>>> class Point2D(TypedDict): pass
>>> Point2D.__total__
True
>>> class Point2D(TypedDict, total=False): pass
>>> Point2D.__total__
False
>>> class Point3D(Point2D): pass
>>> Point3D.__total__
True

Этот атрибут отражает только значение аргумента total для текущего класса TypedDict, а не семантическую полноту класса. Например, у TypedDict со значением __total__ True могут быть ключи, помеченные как NotRequired, либо он может наследоваться от другого TypedDict со значением total=False. Поэтому для интроспекции обычно лучше использовать __required_keys__ и __optional_keys__.

__required_keys__

Добавлено в версии 3.9.

__optional_keys__

Point2D.__required_keys__ и Point2D.__optional_keys__ возвращают объекты frozenset, содержащие соответственно обязательные и необязательные ключи.

Ключи, помеченные как Required, всегда будут входить в __required_keys__, а ключи, помеченные как NotRequired, всегда будут входить в __optional_keys__.

Для обратной совместимости с Python 3.10 и более ранними версиями также можно объявить обязательные и необязательные ключи в одном TypedDict с помощью наследования. Для этого нужно объявить TypedDict с одним значением аргумента total, а затем унаследовать от него в другом TypedDict, указав для total другое значение:

>>> class Point2D(TypedDict, total=False):
...     x: int
...     y: int
...
>>> class Point3D(Point2D):
...     z: int
...
>>> Point3D.__required_keys__ == frozenset({'z'})
True
>>> Point3D.__optional_keys__ == frozenset({'x', 'y'})
True

Добавлено в версии 3.9.

Примечание

Если используется from __future__ import annotations или аннотации заданы в виде строк, при определении TypedDict аннотации не вычисляются. Поэтому интроспекция во время выполнения, на которую опираются __required_keys__ и __optional_keys__, может работать неправильно, а значения атрибутов могут быть неверными.

Дополнительные примеры и подробные правила использования TypedDict см. в PEP 589.

Добавлено в версии 3.8.

Изменено в версии 3.11: Добавлена поддержка пометки отдельных ключей как Required или NotRequired. См. PEP 655.

Изменено в версии 3.11: Добавлена поддержка обобщённых TypedDict.

Протоколы

Модуль typing предоставляет следующие протоколы. Все они декорированы с помощью @runtime_checkable.

class typing.SupportsAbs

ABC с одним абстрактным методом __abs__, ковариантным по возвращаемому типу.

class typing.SupportsBytes

ABC с одним абстрактным методом __bytes__.

class typing.SupportsComplex

ABC с одним абстрактным методом __complex__.

class typing.SupportsFloat

ABC с одним абстрактным методом __float__.

class typing.SupportsIndex

ABC с одним абстрактным методом __index__.

Добавлено в версии 3.8.

class typing.SupportsInt

ABC с одним абстрактным методом __int__.

class typing.SupportsRound

ABC с одним абстрактным методом __round__, ковариантным по возвращаемому типу.

ABC для работы с вводом-выводом

class typing.IO
class typing.TextIO
class typing.BinaryIO

Обобщённый тип IO[AnyStr] и его подклассы TextIO(IO[str]) и BinaryIO(IO[bytes]) представляют типы потоков ввода-вывода, например возвращаемых функцией open().

Функции и декораторы

typing.cast(typ, val)

Привести значение к типу.

Эта функция возвращает значение без изменений. Для системы проверки типов это означает, что возвращаемое значение имеет указанный тип, однако во время выполнения мы намеренно ничего не проверяем (мы хотим, чтобы функция работала как можно быстрее).

typing.assert_type(val, typ, /)

Попросить статическую систему проверки типов подтвердить, что val имеет выведенный тип typ.

Во время выполнения эта функция ничего не делает: она возвращает первый аргумент без изменений, не выполняя проверок и не производя побочных эффектов, независимо от фактического типа аргумента.

Когда статическая система проверки типов встречает вызов assert_type(), она выдаёт ошибку, если значение не имеет указанный тип:

def greet(name: str) -> None:
    assert_type(name, str)  # OK, inferred type of `name` is `str`
    assert_type(name, int)  # type checker error

Эта функция полезна для проверки того, что представление системы проверки типов о скрипте соответствует намерениям разработчика:

def complex_function(arg: object):
    # Do some complex type-narrowing logic,
    # after which we hope the inferred type will be `int`
    ...
    # Test whether the type checker correctly understands our function
    assert_type(arg, int)

Добавлено в версии 3.11.

typing.assert_never(arg, /)

Попросить статическую систему проверки типов подтвердить, что строка кода недостижима.

Пример:

def int_or_str(arg: int | str) -> None:
    match arg:
        case int():
            print("It's an int")
        case str():
            print("It's a str")
        case _ as unreachable:
            assert_never(unreachable)

Здесь аннотации позволяют системе проверки типов вывести, что последний вариант никогда не может быть выполнен, поскольку arg — это либо int, либо str, а оба варианта охвачены предыдущими вариантами.

Если система проверки типов обнаружит, что вызов assert_never() достижим, она выдаст ошибку. Например, если вместо этого аннотация типа для arg была бы int | str | float, система проверки типов выдала бы ошибку, указывающую, что unreachable имеет тип float. Чтобы вызов assert_never прошёл проверку типов, выведенный тип переданного аргумента должен быть нижним типом Never, и никаким другим.

Во время выполнения вызов этой функции вызывает исключение.

См. также

В статье Недостижимый код и проверка полноты вариантов приведены дополнительные сведения о проверке полноты вариантов при статической проверке типов.

Добавлено в версии 3.11.

typing.reveal_type(obj, /)

Попросить статическую систему проверки типов показать выведенный тип выражения.

Когда статическая система проверки типов встречает вызов этой функции, она выводит диагностическое сообщение с выведенным типом аргумента. Например:

x: int = 1
reveal_type(x)  # Revealed type is "builtins.int"

Это может быть полезно, если вы хотите отладить обработку определённого фрагмента кода системой проверки типов.

Во время выполнения эта функция выводит тип аргумента во время выполнения в sys.stderr и возвращает аргумент без изменений (что позволяет использовать вызов в выражении):

x = reveal_type(1)  # prints "Runtime type is int"
print(x)  # prints "1"

Обратите внимание, что тип во время выполнения может отличаться от типа, статически выведенного системой проверки типов (быть более или менее конкретным).

Большинство систем проверки типов поддерживают reveal_type() в любом месте, даже если имя не импортировано из typing. Однако импорт имени из typing позволяет запускать код без ошибок во время выполнения и яснее выражает намерение.

Добавлено в версии 3.11.

@typing.dataclass_transform(*, eq_default=True, order_default=False, kw_only_default=False, field_specifiers=(), **kwargs)

Декоратор для обозначения объекта, обеспечивающего поведение, подобное dataclass.

dataclass_transform можно использовать для декорирования класса, метакласса или функции, которая сама является декоратором. Наличие @dataclass_transform() сообщает статической системе проверки типов, что декорированный объект выполняет во время выполнения «магические» действия, преобразующие класс способом, похожим на @dataclasses.dataclass.

Пример использования с функцией-декоратором:

T = TypeVar("T")

@dataclass_transform()
def create_model(cls: type[T]) -> type[T]:
    ...
    return cls

@create_model
class CustomerModel:
    id: int
    name: str

Для базового класса:

@dataclass_transform()
class ModelBase: ...

class CustomerModel(ModelBase):
    id: int
    name: str

Для метакласса:

@dataclass_transform()
class ModelMeta(type): ...

class ModelBase(metaclass=ModelMeta): ...

class CustomerModel(ModelBase):
    id: int
    name: str

Определённые выше классы CustomerModel системы проверки типов будут обрабатывать так же, как классы, созданные с помощью @dataclasses.dataclass. Например, системы проверки типов будут считать, что у этих классов есть методы __init__, принимающие id и name.

Декорированный класс, метакласс или функция могут принимать следующие логические аргументы, которые системы проверки типов будут считать имеющими тот же эффект, что и у декоратора @dataclasses.dataclass: init, eq, order, unsafe_hash, frozen, match_args, kw_only и slots. Значение этих аргументов (True или False) должно допускать статическое вычисление.

Аргументы декоратора dataclass_transform можно использовать для настройки поведения декорированного класса, метакласса или функции по умолчанию:

Параметры:
  • eq_default (bool) – Указывает, считается ли параметр eq равным True или False, если вызывающий код его не указал. По умолчанию — True.
  • order_default (bool) – Указывает, считается ли параметр order равным True или False, если вызывающий код его не указал. По умолчанию — False.
  • kw_only_default (bool) – Указывает, считается ли параметр kw_only равным True или False, если вызывающий код его не указал. По умолчанию — False.
  • field_specifiers (tuple[Callable[..., Any], ...]) – Задаёт статический список поддерживаемых классов или функций, описывающих поля, подобно dataclasses.field(). По умолчанию — ().
  • **kwargs (Any) – Допускаются любые другие именованные аргументы для обеспечения возможных расширений в будущем.

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

Распознаваемые параметры спецификаторов полей

Имя параметра

Описание

init

Указывает, следует ли включать поле в синтезируемый метод __init__. Если параметр не задан, для init используется значение True.

default

Задаёт значение поля по умолчанию.

default_factory

Задаёт функцию обратного вызова времени выполнения, возвращающую значение поля по умолчанию. Если не указаны ни default, ни default_factory, считается, что у поля нет значения по умолчанию, и при создании экземпляра класса необходимо указать значение.

factory

Псевдоним параметра default_factory для спецификаторов полей.

kw_only

Указывает, следует ли пометить поле как доступное только по ключевому слову. Если значение True, поле будет доступно только по ключевому слову. Если значение False, оно не будет доступно только по ключевому слову. Если параметр не задан, используется значение параметра kw_only у объекта, декорированного с помощью dataclass_transform, а если и он не задан — значение kw_only_default у dataclass_transform.

alias

Задаёт альтернативное имя поля. Это имя используется в синтезируемом методе __init__.

Во время выполнения этот декоратор записывает свои аргументы в атрибут __dataclass_transform__ декорированного объекта. Других эффектов во время выполнения нет.

Подробнее см. PEP 681.

Добавлено в версии 3.11.

@typing.overload

Декоратор для создания перегруженных функций и методов.

Декоратор @overload позволяет описывать функции и методы, поддерживающие несколько различных комбинаций типов аргументов. За последовательностью определений с декоратором @overload должно следовать ровно одно определение без декоратора @overload (для той же функции/метода).

Определения с декоратором @overload предназначены только для системы проверки типов, поскольку они будут переопределены определением без декоратора @overload. Между тем определение без декоратора @overload будет использоваться во время выполнения, но система проверки типов должна его игнорировать. Во время выполнения прямой вызов функции с декоратором @overload вызовет исключение NotImplementedError.

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

@overload
def process(response: None) -> None:
    ...
@overload
def process(response: int) -> tuple[int, str]:
    ...
@overload
def process(response: bytes) -> str:
    ...
def process(response):
    ...  # actual implementation goes here

Дополнительные сведения и сравнение с другими семантиками типизации см. в PEP 484.

Изменено в версии 3.11: Теперь перегруженные функции можно анализировать во время выполнения с помощью get_overloads().

typing.get_overloads(func)

Возвращает последовательность определений функции func, декорированных с помощью @overload.

func — это объект функции, реализующий перегруженную функцию. Например, если определение process из документации к @overload задано, get_overloads(process) вернёт последовательность из трёх объектов-функций для трёх определённых перегрузок. При вызове для функции без перегрузок get_overloads() возвращает пустую последовательность.

get_overloads() можно использовать для анализа перегруженной функции во время выполнения.

Добавлено в версии 3.11.

typing.clear_overloads()

Удаляет все зарегистрированные перегрузки из внутреннего реестра.

Это можно использовать для освобождения памяти, занятой реестром.

Добавлено в версии 3.11.

@typing.final

Декоратор для обозначения финальных методов и классов.

Декорирование метода с помощью @final сообщает системе проверки типов, что метод нельзя переопределить в подклассе. Декорирование класса с помощью @final указывает, что от него нельзя создавать подклассы.

Например:

class Base:
    @final
    def done(self) -> None:
        ...
class Sub(Base):
    def done(self) -> None:  # Error reported by type checker
        ...

@final
class Leaf:
    ...
class Other(Leaf):  # Error reported by type checker
    ...

Во время выполнения эти свойства не проверяются. Подробнее см. PEP 591.

Добавлено в версии 3.8.

Изменено в версии 3.11: Теперь декоратор пытается установить атрибут __final__ со значением True у декорированного объекта. Поэтому во время выполнения можно использовать проверку, например if getattr(obj, "__final__", False), чтобы определить, был ли объект obj помечен как финальный. Если декорированный объект не поддерживает установку атрибутов, декоратор возвращает его без изменений и не вызывает исключение.

@typing.no_type_check

Декоратор для указания, что аннотации не являются подсказками типов.

Работает как декоратор класса или функции. Для класса он рекурсивно применяется ко всем методам и классам, определённым в этом классе (но не к методам, определённым в его суперклассах или подклассах). Системы проверки типов будут игнорировать все аннотации в функции или классе с этим декоратором.

@no_type_check изменяет декорированный объект на месте.

@typing.no_type_check_decorator

Декоратор, придающий другому декоратору эффект no_type_check().

Он оборачивает декоратор в объект, который оборачивает декорированную функцию в no_type_check().

@typing.type_check_only

Декоратор, помечающий класс или функцию как недоступные во время выполнения.

Сам этот декоратор недоступен во время выполнения. В основном он предназначен для пометки классов, определённых в файлах заглушек типов, если реализация возвращает экземпляр закрытого класса:

@type_check_only
class Response:  # private or not available at runtime
    code: int
    def get_header(self, name: str) -> str: ...

def fetch_response() -> Response: ...

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

Вспомогательные средства интроспекции

typing.get_type_hints(obj, globalns=None, localns=None, include_extras=False)

Возвращает словарь подсказок типов для объекта функции, метода, модуля или класса.

Часто это то же самое, что и obj.__annotations__. Кроме того, строки, представляющие прямые ссылки, обрабатываются путём их вычисления в пространствах имён globals и locals. Для класса C возвращается словарь, составленный путём объединения всех __annotations__ вдоль C.__mro__ в обратном порядке.

Функция рекурсивно заменяет все Annotated[T, ...] на T, если только для include_extras не задано значение True (дополнительные сведения см. в разделе Annotated). Например:

class Student(NamedTuple):
    name: Annotated[str, 'some marker']

assert get_type_hints(Student) == {'name': str}
assert get_type_hints(Student, include_extras=False) == {'name': str}
assert get_type_hints(Student, include_extras=True) == {
    'name': Annotated[str, 'some marker']
}

Примечание

get_type_hints() не работает с импортированными псевдонимами типов, содержащими прямые ссылки. Включение отложенного вычисления аннотаций (PEP 563) может устранить необходимость в большинстве прямых ссылок.

Изменено в версии 3.9: В рамках PEP 593 добавлен параметр include_extras. Дополнительные сведения см. в документации по Annotated.

Изменено в версии 3.11: Ранее Optional[t] добавлялся к аннотациям функций и методов, если было задано значение по умолчанию, равное None. Теперь аннотация возвращается без изменений.

typing.get_origin(tp)

Получает тип без параметров типа: для объекта typing вида X[Y, Z, ...] возвращает X.

Если X — это псевдоним из модуля typing для встроенного класса или класса из collections, он будет нормализован до исходного класса. Если X является экземпляром ParamSpecArgs или ParamSpecKwargs, возвращается лежащий в основе ParamSpec. Для неподдерживаемых объектов возвращается None.

Примеры:

assert get_origin(str) is None
assert get_origin(Dict[str, int]) is dict
assert get_origin(Union[int, str]) is Union
P = ParamSpec('P')
assert get_origin(P.args) is P
assert get_origin(P.kwargs) is P

Добавлено в версии 3.8.

typing.get_args(tp)

Получает аргументы типа с учётом всех подстановок: для объекта typing вида X[Y, Z, ...] возвращает (Y, Z, ...).

Если X — это объединение или Literal, содержащиеся в другом обобщённом типе, порядок (Y, Z, ...) может отличаться от исходного порядка аргументов [Y, Z, ...] из-за кэширования типов. Для неподдерживаемых объектов возвращается ().

Примеры:

assert get_args(int) == ()
assert get_args(Dict[int, str]) == (int, str)
assert get_args(Union[int, str]) == (int, str)

Добавлено в версии 3.8.

typing.is_typeddict(tp)

Проверяет, является ли тип TypedDict.

Например:

class Film(TypedDict):
    title: str
    year: int

assert is_typeddict(Film)
assert not is_typeddict(list | str)

# TypedDict is a factory for creating typed dicts,
# not a typed dict itself
assert not is_typeddict(TypedDict)

Добавлено в версии 3.10.

class typing.ForwardRef

Класс для внутреннего представления строковых прямых ссылок в системе типизации.

Например, List["SomeClass"] неявно преобразуется в List[ForwardRef("SomeClass")]. Пользователь не должен создавать экземпляры ForwardRef, однако этот класс может использоваться инструментами интроспекции.

Примечание

Обобщённые типы из PEP 585, такие как list["SomeClass"], не будут неявно преобразованы в list[ForwardRef("SomeClass")] и поэтому не будут автоматически разрешаться в list[SomeClass].

Добавлено в версии 3.7.4.

Константа

typing.TYPE_CHECKING

Специальная константа, которая сторонними статическими системами проверки типов считается равной True. Во время выполнения она равна False.

Использование:

if TYPE_CHECKING:
    import expensive_mod

def fun(arg: 'expensive_mod.SomeType') -> None:
    local_var: expensive_mod.AnotherType = other_fun()

Первая аннотация типа должна быть заключена в кавычки, то есть представлена «прямой ссылкой», чтобы скрыть ссылку expensive_mod от интерпретатора во время выполнения. Аннотации типов локальных переменных не вычисляются, поэтому вторую аннотацию не нужно заключать в кавычки.

Примечание

Если используется from __future__ import annotations, аннотации не вычисляются во время определения функции. Вместо этого они сохраняются в виде строк в __annotations__. Благодаря этому аннотацию не нужно заключать в кавычки (см. PEP 563).

Добавлено в версии 3.5.2.

Устаревшие псевдонимы

Этот модуль определяет несколько устаревших псевдонимов для ранее существовавших классов стандартной библиотеки. Изначально они были включены в модуль typing, чтобы поддержать параметризацию этих обобщённых классов с помощью []. Однако псевдонимы стали избыточными в Python 3.9, когда соответствующие ранее существовавшие классы получили поддержку [] (см. PEP 585).

Эти избыточные типы объявлены устаревшими начиная с Python 3.9. Однако, хотя псевдонимы могут быть удалены в какой-либо момент, их удаление в настоящее время не планируется. Поэтому интерпретатор пока не выдаёт предупреждения об устаревании этих псевдонимов.

Если в какой-либо момент будет принято решение удалить эти устаревшие псевдонимы, интерпретатор будет выдавать предупреждение об устаревании как минимум в течение двух выпусков до удаления. Гарантируется, что псевдонимы останутся в модуле typing без предупреждений об устаревании как минимум до Python 3.14.

Средствам проверки типов рекомендуется отмечать использование устаревших типов, если проверяемая программа рассчитана на минимальную версию Python 3.9 или новее.

Псевдонимы встроенных типов

class typing.Dict(dict, MutableMapping[KT, VT])

Устаревший псевдоним для dict.

Обратите внимание: для аннотирования аргументов предпочтительно использовать абстрактный тип коллекции, например Mapping, а не dict или typing.Dict.

Этот тип можно использовать следующим образом:

def count_words(text: str) -> Dict[str, int]:
    ...

Устарел с версии 3.9: builtins.dict теперь поддерживает индексацию ([]). См. PEP 585 и Тип обобщённого псевдонима.

class typing.List(list, MutableSequence[T])

Устаревший псевдоним для list.

Обратите внимание: для аннотирования аргументов предпочтительно использовать абстрактный тип коллекции, например Sequence или Iterable, а не list или typing.List.

Этот тип можно использовать следующим образом:

T = TypeVar('T', int, float)

def vec2(x: T, y: T) -> List[T]:
    return [x, y]

def keep_positives(vector: Sequence[T]) -> List[T]:
    return [item for item in vector if item > 0]

Устарел с версии 3.9: builtins.list теперь поддерживает индексацию ([]). См. PEP 585 и Тип обобщённого псевдонима.

class typing.Set(set, MutableSet[T])

Устаревший псевдоним для builtins.set.

Обратите внимание: для аннотирования аргументов предпочтительно использовать абстрактный тип коллекции, например AbstractSet, а не set или typing.Set.

Устарел с версии 3.9: builtins.set теперь поддерживает индексацию ([]). См. PEP 585 и Тип обобщённого псевдонима.

class typing.FrozenSet(frozenset, AbstractSet[T_co])

Устаревший псевдоним для builtins.frozenset.

Устарел с версии 3.9: builtins.frozenset теперь поддерживает индексацию ([]). См. PEP 585 и Тип обобщённого псевдонима.

typing.Tuple

Устаревший псевдоним для tuple.

tuple и Tuple являются особыми случаями в системе типов; подробнее см. в разделе Аннотирование кортежей.

Устарел с версии 3.9: builtins.tuple теперь поддерживает индексацию ([]). См. PEP 585 и Тип обобщённого псевдонима.

class typing.Type(Generic[CT_co])

Устаревший псевдоним для type.

Подробнее об использовании type или typing.Type в аннотациях типов см. в разделе Тип объектов классов.

Добавлено в версии 3.5.2.

Устарел с версии 3.9: builtins.type теперь поддерживает индексацию ([]). См. PEP 585 и Тип обобщённого псевдонима.

Псевдонимы типов из collections

class typing.DefaultDict(collections.defaultdict, MutableMapping[KT, VT])

Устаревший псевдоним для collections.defaultdict.

Добавлено в версии 3.5.2.

Устарел с версии 3.9: collections.defaultdict теперь поддерживает индексацию ([]). См. PEP 585 и Тип обобщённого псевдонима.

class typing.OrderedDict(collections.OrderedDict, MutableMapping[KT, VT])

Устаревший псевдоним для collections.OrderedDict.

Добавлено в версии 3.7.2.

Устарел с версии 3.9: collections.OrderedDict теперь поддерживает индексацию ([]). См. PEP 585 и Тип обобщённого псевдонима.

class typing.ChainMap(collections.ChainMap, MutableMapping[KT, VT])

Устаревший псевдоним для collections.ChainMap.

Добавлено в версии 3.6.1.

Устарел с версии 3.9: collections.ChainMap теперь поддерживает индексацию ([]). См. PEP 585 и Тип обобщённого псевдонима.

class typing.Counter(collections.Counter, Dict[T, int])

Устаревший псевдоним для collections.Counter.

Добавлено в версии 3.6.1.

Устарел с версии 3.9: collections.Counter теперь поддерживает индексацию ([]). См. PEP 585 и Тип обобщённого псевдонима.

class typing.Deque(deque, MutableSequence[T])

Устаревший псевдоним для collections.deque.

Добавлено в версии 3.6.1.

Устарел с версии 3.9: collections.deque теперь поддерживает индексацию ([]). См. PEP 585 и Тип обобщённого псевдонима.

Псевдонимы других конкретных типов

class typing.Pattern
class typing.Match

Устаревшие псевдонимы, соответствующие типам возвращаемых значений re.compile() и re.match().

Эти типы (и соответствующие функции) являются обобщёнными относительно AnyStr. Pattern можно специализировать как Pattern[str] или Pattern[bytes]; Match можно специализировать как Match[str] или Match[bytes].

Устарел с версии 3.8, будет удалён в версии 3.13: Пространство имён typing.re объявлено устаревшим и будет удалено. Вместо этого эти типы следует импортировать непосредственно из typing.

Устарел с версии 3.9: Классы Pattern и Match из re теперь поддерживают []. См. PEP 585 и Тип обобщённого псевдонима.

class typing.Text

Устаревший псевдоним для str.

Text предоставлен для обеспечения совместимости кода Python 2 с будущими версиями: в Python 2 Text является псевдонимом unicode.

Используйте Text, чтобы указать, что значение должно содержать строку Unicode, совместимую как с Python 2, так и с Python 3:

def add_unicode_checkmark(text: Text) -> Text:
    return text + u' \u2713'

Добавлено в версии 3.5.2.

Устарел с версии 3.11: Python 2 больше не поддерживается, а большинство средств проверки типов также больше не поддерживают проверку типов кода Python 2. Удаление этого псевдонима в настоящее время не планируется, однако пользователям рекомендуется использовать str вместо Text.

Псевдонимы контейнерных ABC из collections.abc

class typing.AbstractSet(Collection[T_co])

Устаревший псевдоним для collections.abc.Set.

Устарел с версии 3.9: collections.abc.Set теперь поддерживает индексацию ([]). См. PEP 585 и Тип обобщённого псевдонима.

class typing.ByteString(Sequence[int])

Этот тип представляет типы bytes, bytearray и memoryview для последовательностей байтов.

Устарел с версии 3.9, будет удалён в версии 3.14: Предпочтительно использовать typing_extensions.Buffer или объединение, например bytes | bytearray | memoryview.

class typing.Collection(Sized, Iterable[T_co], Container[T_co])

Устаревший псевдоним для collections.abc.Collection.

Добавлено в версии 3.6.

Устарел с версии 3.9: collections.abc.Collection теперь поддерживает индексацию ([]). См. PEP 585 и Тип обобщённого псевдонима.

class typing.Container(Generic[T_co])

Устаревший псевдоним для collections.abc.Container.

Устарел с версии 3.9: collections.abc.Container теперь поддерживает индексацию ([]). См. PEP 585 и Тип обобщённого псевдонима.

class typing.ItemsView(MappingView, AbstractSet[tuple[KT_co, VT_co]])

Устаревший псевдоним для collections.abc.ItemsView.

Устарел с версии 3.9: collections.abc.ItemsView теперь поддерживает индексацию ([]). См. PEP 585 и Тип обобщённого псевдонима.

class typing.KeysView(MappingView, AbstractSet[KT_co])

Устаревший псевдоним для collections.abc.KeysView.

Устарел с версии 3.9: collections.abc.KeysView теперь поддерживает индексацию ([]). См. PEP 585 и Тип обобщённого псевдонима.

class typing.Mapping(Collection[KT], Generic[KT, VT_co])

Устаревший псевдоним для collections.abc.Mapping.

Этот тип можно использовать следующим образом:

def get_position_in_index(word_list: Mapping[str, int], word: str) -> int:
    return word_list[word]

Устарел с версии 3.9: collections.abc.Mapping теперь поддерживает индексацию ([]). См. PEP 585 и Тип обобщённого псевдонима.

class typing.MappingView(Sized)

Устаревший псевдоним для collections.abc.MappingView.

Устарел с версии 3.9: collections.abc.MappingView теперь поддерживает индексацию ([]). См. PEP 585 и Тип обобщённого псевдонима.

class typing.MutableMapping(Mapping[KT, VT])

Устаревший псевдоним для collections.abc.MutableMapping.

Устарел с версии 3.9: collections.abc.MutableMapping теперь поддерживает индексацию ([]). См. PEP 585 и Тип обобщённого псевдонима.

class typing.MutableSequence(Sequence[T])

Устаревший псевдоним для collections.abc.MutableSequence.

Устарел с версии 3.9: collections.abc.MutableSequence теперь поддерживает индексацию ([]). См. PEP 585 и Тип обобщённого псевдонима.

class typing.MutableSet(AbstractSet[T])

Устаревший псевдоним для collections.abc.MutableSet.

Устарел с версии 3.9: collections.abc.MutableSet теперь поддерживает индексацию ([]). См. PEP 585 и Тип обобщённого псевдонима.

class typing.Sequence(Reversible[T_co], Collection[T_co])

Устаревший псевдоним для collections.abc.Sequence.

Устарел с версии 3.9: collections.abc.Sequence теперь поддерживает индексацию ([]). См. PEP 585 и Тип обобщённого псевдонима.

class typing.ValuesView(MappingView, Collection[_VT_co])

Устаревший псевдоним для collections.abc.ValuesView.

Устарел с версии 3.9: collections.abc.ValuesView теперь поддерживает индексацию ([]). См. PEP 585 и Тип обобщённого псевдонима.

Псевдонимы асинхронных ABC в collections.abc

class typing.Coroutine(Awaitable[ReturnType], Generic[YieldType, SendType, ReturnType])

Устаревший псевдоним для collections.abc.Coroutine.

Вариантность и порядок переменных типов соответствуют таковым у Generator, например:

from collections.abc import Coroutine
c: Coroutine[list[str], str, int]  # Some coroutine defined elsewhere
x = c.send('hi')                   # Inferred type of 'x' is list[str]
async def bar() -> None:
    y = await c                    # Inferred type of 'y' is int

Добавлено в версии 3.5.3.

Устарело начиная с версии 3.9: collections.abc.Coroutine теперь поддерживает параметризацию ([]). См. PEP 585 и Тип универсального псевдонима.

class typing.AsyncGenerator(AsyncIterator[YieldType], Generic[YieldType, SendType])

Устаревший псевдоним для collections.abc.AsyncGenerator.

Асинхронный генератор можно аннотировать универсальным типом AsyncGenerator[YieldType, SendType]. Например:

async def echo_round() -> AsyncGenerator[int, float]:
    sent = yield 0
    while sent >= 0.0:
        rounded = await round(sent)
        sent = yield rounded

В отличие от обычных генераторов, асинхронные генераторы не могут возвращать значение, поэтому параметра типа ReturnType нет. Как и в случае с Generator, SendType ведёт себя контравариантно.

Если ваш генератор будет только выдавать значения, задайте для SendType значение None:

async def infinite_stream(start: int) -> AsyncGenerator[int, None]:
    while True:
        yield start
        start = await increment(start)

В качестве альтернативы аннотируйте генератор типом возвращаемого значения AsyncIterable[YieldType] или AsyncIterator[YieldType]:

async def infinite_stream(start: int) -> AsyncIterator[int]:
    while True:
        yield start
        start = await increment(start)

Добавлено в версии 3.6.1.

Устарело начиная с версии 3.9: collections.abc.AsyncGenerator теперь поддерживает параметризацию ([]). См. PEP 585 и Тип универсального псевдонима.

class typing.AsyncIterable(Generic[T_co])

Устаревший псевдоним для collections.abc.AsyncIterable.

Добавлено в версии 3.5.2.

Устарело начиная с версии 3.9: collections.abc.AsyncIterable теперь поддерживает параметризацию ([]). См. PEP 585 и Тип универсального псевдонима.

class typing.AsyncIterator(AsyncIterable[T_co])

Устаревший псевдоним для collections.abc.AsyncIterator.

Добавлено в версии 3.5.2.

Устарело начиная с версии 3.9: collections.abc.AsyncIterator теперь поддерживает параметризацию ([]). См. PEP 585 и Тип универсального псевдонима.

class typing.Awaitable(Generic[T_co])

Устаревший псевдоним для collections.abc.Awaitable.

Добавлено в версии 3.5.2.

Устарело начиная с версии 3.9: collections.abc.Awaitable теперь поддерживает параметризацию ([]). См. PEP 585 и Тип универсального псевдонима.

Псевдонимы других ABC в collections.abc

class typing.Iterable(Generic[T_co])

Устаревший псевдоним для collections.abc.Iterable.

Устарело начиная с версии 3.9: collections.abc.Iterable теперь поддерживает параметризацию ([]). См. PEP 585 и Тип универсального псевдонима.

class typing.Iterator(Iterable[T_co])

Устаревший псевдоним для collections.abc.Iterator.

Устарело начиная с версии 3.9: collections.abc.Iterator теперь поддерживает параметризацию ([]). См. PEP 585 и Тип универсального псевдонима.

typing.Callable

Устаревший псевдоним для collections.abc.Callable.

Подробнее о том, как использовать collections.abc.Callable и typing.Callable в аннотациях типов, см. раздел Аннотирование вызываемых объектов.

Устарело начиная с версии 3.9: collections.abc.Callable теперь поддерживает параметризацию ([]). См. PEP 585 и Тип универсального псевдонима.

Изменено в версии 3.10: Callable теперь поддерживает ParamSpec и Concatenate. Подробнее см. PEP 612.

class typing.Generator(Iterator[YieldType], Generic[YieldType, SendType, ReturnType])

Устаревший псевдоним для collections.abc.Generator.

Генератор можно аннотировать универсальным типом Generator[YieldType, SendType, ReturnType]. Например:

def echo_round() -> Generator[int, float, str]:
    sent = yield 0
    while sent >= 0:
        sent = yield round(sent)
    return 'Done'

Обратите внимание: в отличие от многих других универсальных типов в модуле typing, SendType у Generator ведёт себя контравариантно, а не ковариантно или инвариантно.

Если ваш генератор будет только выдавать значения, задайте для SendType и ReturnType значение None:

def infinite_stream(start: int) -> Generator[int, None, None]:
    while True:
        yield start
        start += 1

В качестве альтернативы аннотируйте генератор типом возвращаемого значения Iterable[YieldType] или Iterator[YieldType]:

def infinite_stream(start: int) -> Iterator[int]:
    while True:
        yield start
        start += 1

Устарело начиная с версии 3.9: collections.abc.Generator теперь поддерживает параметризацию ([]). См. PEP 585 и Тип универсального псевдонима.

class typing.Hashable

Псевдоним для collections.abc.Hashable.

class typing.Reversible(Iterable[T_co])

Устаревший псевдоним для collections.abc.Reversible.

Устарело начиная с версии 3.9: collections.abc.Reversible теперь поддерживает параметризацию ([]). См. PEP 585 и Тип универсального псевдонима.

class typing.Sized

Псевдоним для collections.abc.Sized.

Псевдонимы ABC из contextlib

class typing.ContextManager(Generic[T_co])

Устаревший псевдоним для contextlib.AbstractContextManager.

Добавлено в версии 3.5.4.

Устарело начиная с версии 3.9: contextlib.AbstractContextManager теперь поддерживает параметризацию ([]). См. PEP 585 и Тип универсального псевдонима.

class typing.AsyncContextManager(Generic[T_co])

Устаревший псевдоним для contextlib.AbstractAsyncContextManager.

Добавлено в версии 3.6.2.

Устарело начиная с версии 3.9: contextlib.AbstractAsyncContextManager теперь поддерживает параметризацию ([]). См. PEP 585 и Тип универсального псевдонима.

Сроки прекращения поддержки основных функций

Некоторые функции в typing устарели и могут быть удалены в будущей версии Python. В приведённой ниже таблице для удобства перечислены основные случаи прекращения поддержки. Эти сведения могут измениться, и в таблице указаны не все устаревшие функции.

Функция

Устарела в версии

Предполагаемое удаление

PEP/проблема

Подмодули typing.io и typing.re

3.8

3.13

bpo-38291

Версии typing стандартных коллекций

3.9

Не решено (подробности см. в разделе Устаревшие псевдонимы)

PEP 585

typing.ByteString

3.9

3.14

gh-91896

typing.Text

3.11

Не решено

gh-92332

© 2001–2024 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.11/library/typing.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API