Spec-Zone.ru › Python 3.14

typing — Поддержка аннотаций типов

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

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

Примечание

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

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

Рассмотрим следующую функцию:

def surface_area_of_cube(edge_length: float) -> str:
    return f"The surface area of the cube is {6 * edge_length ** 2}."

Функция surface_area_of_cube принимает аргумент, который должен быть экземпляром float, как указано в аннотации типа edge_length: float. Функция должна возвращать экземпляр str, как указано в аннотации -> str.

Аннотациями типов могут быть простые классы, такие как float или str, но они также могут быть и более сложными. Модуль typing предоставляет набор более сложных аннотаций типов.

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

См. также

Краткая справка по аннотациям типов

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

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

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

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

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

Спецификация системы типов Python

Актуальную официальную спецификацию системы типов Python можно найти на странице «Спецификация системы типов Python».

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

Псевдоним типа определяется с помощью инструкции type, которая создаёт экземпляр TypeAliasType. В этом примере средства статической проверки типов будут считать Vector и list[float] эквивалентными:

type 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

type ConnectionOptions = dict[str, str]
type Address = tuple[str, int]
type 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:
    ...

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

Vector = list[float]

Или пометить с помощью 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.

Примечание

Напомним, что использование псевдонима типа объявляет два типа эквивалентными. Выражение type 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: ...

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

from collections.abc import Sequence

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

Или напрямую с помощью фабрики TypeVar:

from collections.abc import Sequence
from typing import TypeVar

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

def second(l: Sequence[U]) -> U:  # Function is generic over the TypeVar "U"
    return l[1]

Изменено в версии 3.12: Синтаксическая поддержка обобщённых типов появилась в Python 3.12.

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

Для большинства контейнеров в 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.

Аннотирование генераторов и сопрограмм

Генератор можно аннотировать с помощью обобщённого типа Generator[YieldType, SendType, ReturnType]. Например:

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

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

Параметры SendType и ReturnType по умолчанию равны None:

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

Эти типы также можно задать явно:

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

Асинхронные генераторы обрабатываются похожим образом, но для них не указывается аргумент типа ReturnType (AsyncGenerator[YieldType, SendType]). Аргумент SendType по умолчанию равен None, поэтому следующие определения эквивалентны:

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

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)

Сопрограммы можно аннотировать с помощью Coroutine[YieldType, SendType, ReturnType]. Обобщённые аргументы соответствуют аргументам 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

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

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

from logging import Logger

class LoggedVar[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)

Этот синтаксис указывает, что класс LoggedVar параметризован одной переменной типа T . Это также делает T допустимым типом в теле класса.

Обобщённые классы неявно наследуются от Generic. Для совместимости с Python 3.11 и более ранними версиями можно также явно наследоваться от Generic, чтобы объявить класс обобщённым:

from typing import TypeVar, Generic

T = TypeVar('T')

class LoggedVar(Generic[T]):
    ...

У обобщённых классов есть методы __class_getitem__(), поэтому их можно параметризовать во время выполнения (например, как LoggedVar[int] ниже):

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

class WeirdTrio[T, B: Sequence[bytes], S: (int, str)]:
    ...

OldT = TypeVar('OldT', contravariant=True)
OldB = TypeVar('OldB', bound=Sequence[bytes], covariant=True)
OldS = TypeVar('OldS', int, str)

class OldWeirdTrio(Generic[OldT, OldB, OldS]):
    ...

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

from typing import TypeVar, Generic
...

class Pair[M, M]:  # SyntaxError
    ...

T = TypeVar('T')

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

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

from collections.abc import Sized

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

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

from collections.abc import Mapping

class MyDict[T](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

type Response[S] = Iterable[S] | int

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

type Vec[T] = Iterable[tuple[T, T]]

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

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

from collections.abc import Iterable
from typing import TypeVar

S = TypeVar("S")
Response = Iterable[S] | int

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

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

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

>>> class Z[T, **P]: ...  # T is a TypeVar; P is a ParamSpec
...
>>> Z[int, [dict, float]]
__main__.Z[int, [dict, float]]

Классы, обобщённые по ParamSpec, также можно создавать с помощью явного наследования от Generic. В этом случае ** не используется:

from typing import ParamSpec, Generic

P = ParamSpec('P')

class Z(Generic[P]):
    ...

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

>>> class X[**P]: ...
...
>>> X[int, str]
__main__.X[[int, str]]
>>> X[[int, str]]
__main__.X[[int, 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 assignable to 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!"

Устарело с версии 3.13, будет удалено в версии 3.18: Устарело в пользу нового синтаксиса параметров типа. Используйте class A[T: (str, bytes)]: ... вместо импорта AnyStr. Подробнее см. в PEP 695.

В Python 3.16 AnyStr будет удалён из typing.__all__, а при обращении к нему или его импорте из typing во время выполнения будут выдаваться предупреждения об устаревании. AnyStr будет удалён из typing в Python 3.18.

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
typing.NoReturn

Never и NoReturn обозначают нижний тип — тип, у которого нет элементов.

Их можно использовать, чтобы указать, что функция никогда не возвращает управление, например sys.exit():

from typing import Never  # or NoReturn

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

Или чтобы определить функцию, которую никогда не следует вызывать, поскольку для неё нет допустимых аргументов, например assert_never():

from typing import Never  # or NoReturn

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 (or NoReturn)

Never и NoReturn имеют одинаковый смысл в системе типов, и статические средства проверки типов рассматривают их как эквивалентные.

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

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

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 особенно полезен в старых версиях Python для аннотирования псевдонимов, использующих отложенные ссылки, поскольку средствам проверки типов может быть сложно отличить их от обычных присваиваний переменным:

from typing import Generic, TypeAlias, TypeVar

T = TypeVar("T")

# "Box" does not exist yet,
# so we have to use quotes for the forward reference on Python <3.12.
# 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.

Устарело с версии 3.12: TypeAlias устарел в пользу инструкции type, которая создаёт экземпляры TypeAliasType и изначально поддерживает отложенные ссылки. Обратите внимание: хотя TypeAlias и TypeAliasType служат схожим целям и имеют похожие названия, это разные объекты, и второй не является типом первого. Удаление TypeAlias пока не планируется, однако пользователям рекомендуется перейти на инструкции type.

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

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

class typing.Union

Тип объединения; Union[X, Y] эквивалентно X | Y и означает X или Y.

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

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

    Union[Union[int, str], float] == Union[int, str, float]
    

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

    type A = Union[int, str]
    Union[A, 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. См. выражения типа объединения.

Изменено в версии 3.14: types.UnionType теперь является псевдонимом для Union, а Union[int, str] и int | str создают экземпляры одного и того же класса. Чтобы во время выполнения проверить, является ли объект Union, используйте isinstance(obj, Union). Для совместимости с более ранними версиями Python используйте get_origin(obj) is typing.Union or get_origin(obj) is types.UnionType.

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 и при создании экземпляров пользовательских обобщённых классов с параметрами ParamSpec. Последний параметр Concatenate должен быть ParamSpec или многоточием (...).

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

from collections.abc import Callable
from threading import Lock
from typing import Concatenate

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

def with_lock[**P, R](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
    ...

type Mode = 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.

Дополнительные сведения:

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

    assert Literal[Literal[1, 2], 3] == Literal[1, 2, 3]
    

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

    type A = Literal[1, 2]
    assert Literal[A, 3] != Literal[1, 2, 3]
    
  • Избыточные аргументы пропускаются, например:

    assert Literal[1, 2, 1] == Literal[1, 2]
    
  • При сравнении литералов порядок аргументов игнорируется, например:

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

Добавлено в версии 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.

Изменено в версии 3.13: Теперь ClassVar можно вкладывать в Final, и наоборот.

typing.Final

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

Имена Final нельзя переопределять в любой области видимости. Имена 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.

Изменено в версии 3.13: Теперь Final можно вкладывать в ClassVar, и наоборот.

typing.Required

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

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

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

typing.NotRequired

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

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

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

typing.ReadOnly

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

Например:

class Movie(TypedDict):
   title: ReadOnly[str]
   year: int

def mutate_movie(m: Movie) -> None:
   m["year"] = 1999  # allowed
   m["title"] = "The Matrix"  # type checker error

Это свойство не проверяется во время выполнения.

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

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

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

a1 = Annotated[int, ValueRange(3, 10), ctype("char")]
a2 = Annotated[int, ctype("char"), ValueRange(3, 10)]

assert a1 != a2  # Order matters

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

Вложенные типы Annotated уплощаются. Порядок элементов метаданных начинается с самой внутренней аннотации:

assert Annotated[Annotated[int, ValueRange(3, 10)], ctype("char")] == Annotated[
    int, ValueRange(3, 10), ctype("char")
]

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

type From3To10[T] = Annotated[T, ValueRange(3, 10)]
assert Annotated[From3To10[int], 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

type Vec[T] = Annotated[list[tuple[T, T]], MaxLen(10)]

# When used in a type annotation, a type checker will treat "V" the same as
# ``Annotated[list[tuple[int, int]], MaxLen(10)]``:
type V = Vec[int]

Annotated нельзя использовать с распакованным TypeVarTuple:

type Variadic[*Ts] = Annotated[*Ts, Ann1] = Annotated[T1, T2, T3, ..., Ann1]  # NOT valid

где 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')

Чтобы получить исходный тип, обёрнутый в Annotated, используйте атрибут __origin__:

>>> from typing import Annotated, get_origin
>>> Password = Annotated[str, "secret"]
>>> Password.__origin__
<class 'str'>

Обратите внимание, что вызов get_origin() вернёт сам Annotated:

>>> get_origin(Password)
typing.Annotated

См. также

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

PEP, в рамках которого Annotated была добавлена в стандартную библиотеку.

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

typing.TypeIs

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

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

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

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

Иногда удобно использовать пользовательскую логическую функцию в качестве предиката типа. В качестве возвращаемого типа такой функции следует указать TypeIs[...] или TypeGuard, чтобы сообщить статическим средствам проверки типов о таком намерении. Обычно TypeIs ведёт себя интуитивнее, чем TypeGuard, но его нельзя использовать, когда входной и выходной типы несовместимы (например, list[object] с list[int]) или когда функция не возвращает True для всех экземпляров сужаемого типа.

Использование -> TypeIs[NarrowedType] сообщает статическому средству проверки типов следующее о заданной функции:

  1. Возвращаемое значение является логическим.
  2. Если возвращаемое значение — True, тип аргумента представляет собой пересечение исходного типа аргумента и NarrowedType.
  3. Если возвращаемое значение — False, тип аргумента сужается и исключает NarrowedType.

Например:

from typing import assert_type, final, TypeIs

class Parent: pass
class Child(Parent): pass
@final
class Unrelated: pass

def is_parent(val: object) -> TypeIs[Parent]:
    return isinstance(val, Parent)

def run(arg: Child | Unrelated):
    if is_parent(arg):
        # Type of ``arg`` is narrowed to the intersection
        # of ``Parent`` and ``Child``, which is equivalent to
        # ``Child``.
        assert_type(arg, Child)
    else:
        # Type of ``arg`` is narrowed to exclude ``Parent``,
        # so only ``Unrelated`` is left.
        assert_type(arg, Unrelated)

Тип внутри TypeIs должен соответствовать типу аргумента функции; в противном случае статические средства проверки типов выдадут ошибку. Неправильно написанная функция TypeIs может привести к некорректному поведению системы типов; пользователь несёт ответственность за написание таких функций с соблюдением типовой безопасности.

Если функция TypeIs является методом класса или экземпляра, тип в TypeIs соответствует типу второго параметра (после cls или self).

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

TypeIs также работает с переменными типа. Дополнительные сведения см. в PEP 742 (сужение типов с помощью TypeIs).

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

typing.TypeGuard

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

Функции-предикаты типов — это пользовательские функции, возвращающие результат проверки того, является ли их аргумент экземпляром определённого типа. TypeGuard работает аналогично TypeIs, но оказывает несколько иное влияние на проверку типов (см. ниже).

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

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

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

Например:

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!")

TypeIs и TypeGuard различаются следующим образом:

  • TypeIs требует, чтобы сужаемый тип был подтипом входного типа, тогда как TypeGuard этого не требует. Основная причина — возможность сужать, например, list[object] до list[str], несмотря на то что последний не является подтипом первого, поскольку list инвариантен.
  • Когда функция TypeGuard возвращает True, средства проверки типов сужают тип переменной точно до типа TypeGuard. Когда функция TypeIs возвращает True, средства проверки типов могут вывести более точный тип, объединяющий ранее известный тип переменной с типом TypeIs. (Технически это называется типом-пересечением.)
  • Когда функция TypeGuard возвращает False, средства проверки типов не могут сузить тип переменной. Когда функция TypeIs возвращает False, средства проверки типов могут сузить тип переменной, исключив тип TypeIs.

Добавлено в версии 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

Unpack также можно использовать вместе с typing.TypedDict для типизации **kwargs в сигнатуре функции:

from typing import TypedDict, Unpack

class Movie(TypedDict):
    name: str
    year: int

# This function expects two keyword arguments - `name` of type `str`
# and `year` of type `int`.
def foo(**kwargs: Unpack[Movie]): ...

Подробнее об использовании Unpack для типизации **kwargs см. в PEP 692.

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

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

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

Эти объекты можно создавать с помощью специального синтаксиса (списков параметров типа и оператора type). Для совместимости с Python 3.11 и более ранними версиями их также можно создавать без специального синтаксиса, как описано ниже.

class typing.Generic

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

Обычно обобщённый тип объявляется добавлением списка параметров типа после имени класса:

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

Такой класс неявно наследуется от Generic. Семантика этого синтаксиса во время выполнения описана в Справочнике по языку.

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

def lookup_name[X, Y](mapping: Mapping[X, Y], key: X, default: Y) -> Y:
    try:
        return mapping[key]
    except KeyError:
        return default

Здесь квадратные скобки после имени функции указывают на обобщённую функцию.

Для обратной совместимости обобщённые классы также можно объявлять, явно наследуясь от Generic. В этом случае параметры типа необходимо объявить отдельно:

KT = TypeVar('KT')
VT = TypeVar('VT')

class Mapping(Generic[KT, VT]):
    def __getitem__(self, key: KT) -> VT:
        ...
        # Etc.
class typing.TypeVar(name, *constraints, bound=None, covariant=False, contravariant=False, infer_variance=False, default=typing.NoDefault)

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

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

class Sequence[T]:  # T is a TypeVar
    ...

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

class StrSequence[S: str]:  # S is a TypeVar with a `str` upper bound;
    ...                     # we can say that S is "bounded by `str`"


class StrOrBytesSequence[A: (str, bytes)]:  # A is a TypeVar constrained to str or bytes
    ...

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

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[T](x: T, n: int) -> Sequence[T]:
    """Return a list containing n references to x."""
    return [x]*n


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


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

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

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

Семантика переменных типа с верхней границей и переменных типа с ограничениями различается по нескольким важным аспектам. Использование переменной типа с верхней границей означает, что 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 или Protocol) или даже объединение типов:

# Can be anything with an __abs__ method
def print_abs[T: SupportsAbs](arg: T) -> None:
    print("Absolute value:", abs(arg))

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__

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

__infer_variance__

Указывает, следует ли анализаторам типов выводить вариантность переменной типа.

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

__bound__

Верхняя граница переменной типа, если она задана.

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

evaluate_bound()

Функция вычисления, соответствующая атрибуту __bound__. При непосредственном вызове этот метод поддерживает только формат VALUE, который эквивалентен прямому обращению к атрибуту __bound__, однако объект метода можно передать в annotationlib.call_evaluate_function(), чтобы вычислить значение в другом формате.

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

__constraints__

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

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

evaluate_constraints()

Функция вычисления, соответствующая атрибуту __constraints__. При непосредственном вызове этот метод поддерживает только формат VALUE, который эквивалентен прямому обращению к атрибуту __constraints__, однако объект метода можно передать в annotationlib.call_evaluate_function(), чтобы вычислить значение в другом формате.

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

__default__

Значение по умолчанию переменной типа или typing.NoDefault, если значение по умолчанию не задано.

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

evaluate_default()

Функция вычисления, соответствующая атрибуту __default__. При непосредственном вызове этот метод поддерживает только формат VALUE, который эквивалентен прямому обращению к атрибуту __default__, однако объект метода можно передать в annotationlib.call_evaluate_function(), чтобы вычислить значение в другом формате.

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

has_default()

Возвращает признак наличия у переменной типа значения по умолчанию. Это эквивалентно проверке, что __default__ не является синглтоном typing.NoDefault, но при этом не вызывает вычисление значения по умолчанию, вычисляемого отложенно.

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

Изменено в версии 3.12: Теперь переменные типа можно объявлять с помощью синтаксиса параметров типа, представленного в PEP 695. Добавлен параметр infer_variance.

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

class typing.TypeVarTuple(name, *, default=typing.NoDefault)

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

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

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

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

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

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

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

# 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

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

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

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

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

class Array2[*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[*Shape, *Shape]:  # Not valid
    pass

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

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

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

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

__name__

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

__default__

Значение по умолчанию кортежа переменных типа или typing.NoDefault, если значение по умолчанию не задано.

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

evaluate_default()

Функция вычисления, соответствующая атрибуту __default__. При непосредственном вызове этот метод поддерживает только формат VALUE, который эквивалентен прямому обращению к атрибуту __default__, однако объект метода можно передать в annotationlib.call_evaluate_function(), чтобы вычислить значение в другом формате.

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

has_default()

Возвращает признак наличия у кортежа переменных типа значения по умолчанию. Это эквивалентно проверке, что __default__ не является синглтоном typing.NoDefault, но при этом не вызывает вычисление значения по умолчанию, вычисляемого отложенно.

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

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

Изменено в версии 3.12: Теперь кортежи переменных типа можно объявлять с помощью синтаксиса параметров типа, представленного в PEP 695.

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

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

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

В списках параметров типа спецификации параметров можно объявлять с помощью двух звёздочек (**):

type IntFunc[**P] = Callable[P, int]

Для совместимости с Python 3.11 и более ранними версиями объекты ParamSpec также можно создавать следующим образом:

P = ParamSpec('P')

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

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

from collections.abc import Callable
import logging

def add_logging[T, **P](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__

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

__default__

Значение по умолчанию спецификации параметров или typing.NoDefault, если значение по умолчанию не задано.

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

evaluate_default()

Функция вычисления, соответствующая атрибуту __default__. При непосредственном вызове этот метод поддерживает только формат VALUE, который эквивалентен прямому обращению к атрибуту __default__, однако объект метода можно передать в annotationlib.call_evaluate_function(), чтобы вычислить значение в другом формате.

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

has_default()

Возвращает признак наличия у спецификации параметров значения по умолчанию. Это эквивалентно проверке, что __default__ не является синглтоном typing.NoDefault, но при этом не вызывает вычисление значения по умолчанию, вычисляемого отложенно.

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

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

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

Изменено в версии 3.12: Теперь спецификации параметров можно объявлять с помощью синтаксиса параметров типа, представленного в PEP 695.

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

Примечание

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

См. также

  • PEP 612 — Переменные спецификации параметров (PEP, в котором представлены ParamSpec и Concatenate)
  • Concatenate
  • Аннотирование вызываемых объектов
class typing.ParamSpecArgs
class 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.TypeAliasType(name, value, *, type_params=())

Тип псевдонимов типов, созданных с помощью оператора type.

Пример:

>>> type Alias = int
>>> type(Alias)
<class 'typing.TypeAliasType'>

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

__name__

Имя псевдонима типа:

>>> type Alias = int
>>> Alias.__name__
'Alias'
__module__

Имя модуля, в котором был определён псевдоним типа:

>>> type Alias = int
>>> Alias.__module__
'__main__'
__type_params__

Параметры типа псевдонима или пустой кортеж, если псевдоним не является обобщённым:

>>> type ListOrSet[T] = list[T] | set[T]
>>> ListOrSet.__type_params__
(T,)
>>> type NotGeneric = int
>>> NotGeneric.__type_params__
()
__value__

Значение псевдонима типа. Оно вычисляется отложенно, поэтому имена, использованные в определении псевдонима, разрешаются только при обращении к атрибуту __value__:

>>> type Mutually = Recursive
>>> type Recursive = Mutually
>>> Mutually
Mutually
>>> Recursive
Recursive
>>> Mutually.__value__
Recursive
>>> Recursive.__value__
Mutually
evaluate_value()

Функция вычисления, соответствующая атрибуту __value__. При непосредственном вызове этот метод поддерживает только формат VALUE, который эквивалентен прямому обращению к атрибуту __value__, однако объект метода можно передать в annotationlib.call_evaluate_function(), чтобы вычислить значение в другом формате:

>>> type Alias = undefined
>>> Alias.__value__
Traceback (most recent call last):
...
NameError: name 'undefined' is not defined
>>> from annotationlib import Format, call_evaluate_function
>>> Alias.evaluate_value(Format.VALUE)
Traceback (most recent call last):
...
NameError: name 'undefined' is not defined
>>> call_evaluate_function(Alias.evaluate_value, Format.FORWARDREF)
ForwardRef('undefined')

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

Распаковка

Псевдонимы типов поддерживают распаковку со звёздочкой с помощью синтаксиса *Alias. Это эквивалентно непосредственному использованию Unpack[Alias]:

>>> type Alias = tuple[int, str]
>>> type Unpacked = tuple[bool, *Alias]
>>> Unpacked.__value__
tuple[bool, typing.Unpack[Alias]]

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

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

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

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

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

Типы для каждого имени поля можно получить, вызвав annotationlib.get_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[T](NamedTuple):
    key: T
    group: list[T]

Использование с обратной совместимостью:

# For creating a generic NamedTuple on Python 3.11
T = TypeVar("T")

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

# A functional syntax is also supported
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.9: NamedTuple теперь является функцией, а не классом. Его по-прежнему можно использовать в качестве базового класса, как описано выше.

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

Изменено в версии 3.14: Использование super() (и переменной замыкания __class__ closure variable) в методах подклассов NamedTuple не поддерживается и вызывает TypeError.

Устарело с версии 3.13, будет удалено в версии 3.15: Недокументированный синтаксис с аргументами-ключевыми словами для создания классов NamedTuple (NT = NamedTuple("NT", x=int)) устарел и будет запрещён в версии 3.15. Вместо него используйте синтаксис на основе класса или функциональный синтаксис.

Устарело с версии 3.13, будет удалено в версии 3.15: При использовании функционального синтаксиса для создания класса NamedTuple отсутствие значения для параметра ‘fields’ (NT = NamedTuple("NT")) считается устаревшим. Передача None параметру ‘fields’ (NT = NamedTuple("NT", None)) также считается устаревшей. Оба варианта будут запрещены в Python 3.15. Чтобы создать класс NamedTuple без полей, используйте class NT(NamedTuple): pass или NT = NamedTuple("NT", []).

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 (описанного ниже), работают как простые протоколы времени выполнения, проверяющие только наличие заданных атрибутов и игнорирующие их сигнатуры и типы. Классы-протоколы без этого декоратора нельзя использовать в качестве второго аргумента isinstance() или issubclass().

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

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

В коде, который должен быть совместим с Python 3.11 и более ранними версиями, обобщённые протоколы можно записать так:

T = TypeVar("T")

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

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

@typing.runtime_checkable

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

Такой протокол можно использовать с isinstance() и issubclass(). Это позволяет выполнять простую структурную проверку, очень похожую на проверки «узкоспециализированных» классов в 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)

Этот декоратор вызывает TypeError, если применён к классу, который не является протоколом.

Примечание

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

Примечание

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

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

Изменено в версии 3.12: Внутренняя реализация проверок isinstance() для протоколов времени выполнения теперь использует inspect.getattr_static() для поиска атрибутов (ранее использовался hasattr()). В результате некоторые объекты, которые раньше считались экземплярами протокола времени выполнения, в Python 3.12 и более поздних версиях могут больше не считаться его экземплярами, и наоборот. Большинство пользователей это изменение, скорее всего, не затронет.

Изменено в версии 3.12: Сразу после создания класса состав его протокола времени выполнения теперь считается «зафиксированным». Изменение атрибутов такого протокола во время выполнения по-прежнему возможно, но не влияет на проверки isinstance(), сравнивающие объекты с этим протоколом. Подробнее см. в разделе Что нового в Python 3.12.

class typing.TypedDict(dict)

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

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')

Другой способ создать TypedDict — использовать синтаксис вызова функции. Второй аргумент должен быть литералом dict:

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

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

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

class Definition(TypedDict):
    __schema: str  # mangled to `_Definition__schema`

# OK, functional syntax
Point2D = TypedDict('Point2D', {'in': int, 'x-y': int})
Definition = TypedDict('Definition', {'__schema': str})  # not mangled

По умолчанию в 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 для параметра totality:

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

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

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

Отдельные ключи total=False TypedDict можно сделать обязательными с помощью 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 может быть обобщённым:

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

Чтобы создать обобщённый TypedDict, совместимый с Python 3.11 и более ранними версиями, явно унаследуйте его от Generic:

T = TypeVar("T")

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

Тип TypedDict можно исследовать с помощью annotationlib.get_annotations() (дополнительные сведения о рекомендуемых практиках работы с аннотациями см. в разделе Рекомендации по использованию аннотаций) и следующих атрибутов:

__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__, может работать неправильно, а значения атрибутов могут быть ошибочными.

Поддержка ReadOnly отражена в следующих атрибутах:

__readonly_keys__

Объект frozenset, содержащий имена всех ключей, доступных только для чтения. Ключи доступны только для чтения, если они помечены квалификатором ReadOnly.

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

__mutable_keys__

Объект frozenset, содержащий имена всех изменяемых ключей. Ключи являются изменяемыми, если они не помечены квалификатором ReadOnly.

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

Дополнительные примеры и подробные правила см. в разделе TypedDict документации по typing.

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

Изменено в версии 3.9: TypedDict теперь является функцией, а не классом. Его по-прежнему можно использовать в качестве базового класса, как описано выше.

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

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

Изменено в версии 3.13: Удалена поддержка создания TypedDict с помощью аргументов-ключевых слов.

Изменено в версии 3.13: Добавлена поддержка квалификатора ReadOnly.

Устарело с версии 3.13, будет удалено в версии 3.15: При использовании функционального синтаксиса для создания класса TypedDict отсутствие значения для параметра ‘fields’ (TD = TypedDict("TD")) считается устаревшим. Передача None параметру ‘fields’ (TD = TypedDict("TD", None)) также считается устаревшей. Оба варианта будут запрещены в Python 3.15. Чтобы создать класс TypedDict без полей, используйте class TD(TypedDict): pass или TD = TypedDict("TD", {}).

Протоколы

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

class typing.SupportsAbs

Протокол с одним абстрактным методом __abs__, ковариантным по типу возвращаемого значения.

class typing.SupportsBytes

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

class typing.SupportsComplex

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

class typing.SupportsFloat

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

class typing.SupportsIndex

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

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

class typing.SupportsInt

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

class typing.SupportsRound

Протокол с одним абстрактным методом __round__, ковариантным по типу возвращаемого значения.

Абстрактные базовые классы и протоколы для работы с вводом-выводом

class typing.IO[AnyStr]
class typing.TextIO
class typing.BinaryIO

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

Протоколы io.Reader и io.Writer предлагают более простой вариант для типов аргументов, если используются только методы read() или write() соответственно:

def read_and_write(reader: Reader[str], writer: Writer[bytes]):
    data = reader.read()
    writer.write(data.encode())

Для перебора строк входного потока также можно использовать collections.abc.Iterable:

def read_config(stream: Iterable[str]):
    for line in stream:
        ...

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

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() достижим, оно выдаст ошибку. Например, если вместо int | str | float в аннотации типа для arg был бы указан тип, средство проверки типов выдало бы ошибку, указывающую, что 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, frozen_default=False, field_specifiers=(), **kwargs)

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

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

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

@dataclass_transform()
def create_model[T](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.
  • frozen_default (bool) –

    Указывает, считается ли параметр frozen равным True или False, если вызывающий код его не указал. По умолчанию — False.

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

  • 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().

Устарел начиная с версии 3.13; будет удален в версии 3.15: Средства проверки типов так и не добавили поддержку @no_type_check_decorator. Поэтому он объявлен устаревшим и будет удален в Python 3.15.

@typing.override

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

Средства проверки типов должны выдавать ошибку, если метод с декоратором @override фактически ничего не переопределяет. Это помогает предотвратить ошибки, которые могут возникнуть, если базовый класс изменен, а в дочерний класс не внесены соответствующие изменения.

Например:

class Base:
    def log_status(self) -> None:
        ...

class Sub(Base):
    @override
    def log_status(self) -> None:  # Okay: overrides Base.log_status
        ...

    @override
    def done(self) -> None:  # Error reported by type checker
        ...

Проверка этого свойства во время выполнения не производится.

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

Дополнительные сведения см. в PEP 698.

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

@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, *, format=Format.VALUE)

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

Часто результат совпадает с результатом annotationlib.get_annotations(), но эта функция вносит в словарь аннотаций следующие изменения:

  • Строковые литералы и объекты ForwardRef, представляющие отложенные ссылки, обрабатываются путем их вычисления в пространствах имен globalns, localns и, если применимо, параметров типа объекта obj. Если globalns или localns не задан, подходящие словари пространств имен определяются на основе obj.
  • None заменяется на types.NoneType.
  • Если к obj применен @no_type_check, возвращается пустой словарь.
  • Если obj — класс C, функция возвращает словарь, объединяющий аннотации базовых классов C с аннотациями самого C. Для этого функция проходит по C.__mro__ и последовательно объединяет аннотации каждого базового класса. Аннотации классов, стоящих раньше в порядке разрешения методов, всегда имеют приоритет над аннотациями классов, стоящих позже.
  • Функция рекурсивно заменяет все вхождения Annotated[T, ...], Required[T], NotRequired[T] и ReadOnly[T] на T, если только для include_extras не задано значение True (подробности см. в документации к Annotated).

Предупреждение

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

Примечание

Если используется Format.VALUE и какие-либо отложенные ссылки в аннотациях obj не удается разрешить, возникает исключение NameError. Например, это может произойти с именами, импортированными при помощи if TYPE_CHECKING. В более общем случае может возникнуть исключение любого типа, если аннотация содержит недопустимый код Python.

Примечание

Вызов get_type_hints() для экземпляра не поддерживается. Чтобы получить аннотации экземпляра, вызовите get_type_hints() для его класса (например, get_type_hints(type(obj))).

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

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

Изменено в версии 3.14: Добавлен параметр format. Дополнительные сведения см. в документации к annotationlib.get_annotations().

Изменено в версии 3.14: Вызов get_type_hints() для экземпляров больше не поддерживается. В более ранних версиях некоторые экземпляры принимались в качестве недокументированной детали реализации.

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
assert get_origin(Annotated[str, "metadata"]) is Annotated
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.get_protocol_members(tp)

Возвращает набор членов, определенных в Protocol.

>>> from typing import Protocol, get_protocol_members
>>> class P(Protocol):
...     def a(self) -> str: ...
...     b: int
>>> get_protocol_members(P) == frozenset({'a', 'b'})
True

Для аргументов, не являющихся протоколами, возбуждает исключение TypeError.

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

typing.is_protocol(tp)

Определить, является ли тип Protocol.

Например:

class P(Protocol):
    def a(self) -> str: ...
    b: int

assert is_protocol(P)
assert not is_protocol(int)

Эта функция возвращает true только для классов Protocol, но не для их обобщенных псевдонимов:

class GenericP[T](Protocol):
    def a(self) -> T: ...
    b: int

assert not is_protocol(GenericP[int])

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

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)

Эта функция возвращает true только для классов TypedDict, но не для их обобщенных псевдонимов:

class GenericFilm[T](TypedDict):
    title: str
    year: T

assert not is_typeddict(GenericFilm[int])

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

class typing.ForwardRef

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

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

Примечание

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

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

Изменено в версии 3.14: Теперь это псевдоним для annotationlib.ForwardRef. Некоторые недокументированные особенности поведения этого класса изменились; например, после вычисления ForwardRef вычисленное значение больше не кэшируется.

typing.evaluate_forward_ref(forward_ref, *, owner=None, globals=None, locals=None, type_params=None, format=annotationlib.Format.VALUE)

Вычислить annotationlib.ForwardRef как подсказку типа.

Это похоже на вызов annotationlib.ForwardRef.evaluate(), но, в отличие от этого метода, evaluate_forward_ref() также рекурсивно вычисляет отложенные ссылки, вложенные в подсказку типа.

Значения параметров owner, globals, locals, type_params и format описаны в документации к annotationlib.ForwardRef.evaluate().

Предупреждение

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

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

typing.NoDefault

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

>>> T = TypeVar("T")
>>> T.__default__ is typing.NoDefault
True
>>> S = TypeVar("S", default=None)
>>> S.__default__ is None
True

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

Константа

typing.TYPE_CHECKING

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

Модуль, импорт которого требует значительных ресурсов и который содержит только типы, используемые в аннотациях типов, можно безопасно импортировать внутри блока if TYPE_CHECKING:. Это предотвращает фактический импорт модуля во время выполнения; аннотации не вычисляются немедленно (см. PEP 649), поэтому использование неопределённых символов в аннотациях безвредно, если впоследствии вы не будете их анализировать. Во время статического анализа типов ваш инструмент статического анализа типов установит TYPE_CHECKING в значение True, а это означает, что модуль будет импортирован и типы будут корректно проверены в ходе такого анализа.

Пример использования:

if TYPE_CHECKING:
    import expensive_mod

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

Если иногда вам нужно анализировать во время выполнения аннотации типов, которые могут содержать неопределённые символы, используйте annotationlib.get_annotations() с параметром format, равным annotationlib.Format.STRING или annotationlib.Format.FORWARDREF, чтобы безопасно получить аннотации, не вызывая исключение NameError.

Добавлено в версии 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.

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

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

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

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

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

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

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

Обратите внимание: для аннотирования аргументов предпочтительно использовать абстрактный тип коллекции, например collections.abc.Set, а не 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.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.

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

class typing.AbstractSet(Collection[T_co])

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

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

class typing.ByteString(Sequence[int])

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

Используйте isinstance(obj, collections.abc.Buffer), чтобы проверить во время выполнения, реализует ли obj буферный протокол. В аннотациях типов используйте либо Buffer, либо объединение типов, в котором явно перечислены типы, поддерживаемые вашим кодом (например, bytes | bytearray | memoryview).

Изначально ByteString задумывался как абстрактный класс, который служил бы суперклассом для bytes и bytearray. Однако, поскольку у ABC никогда не было методов, знание о том, что объект является экземпляром ByteString, на деле ничего полезного об объекте не сообщало. Другие распространённые типы буферов, например memoryview, также никогда не считались подтипами ByteString (ни во время выполнения, ни средствами статической проверки типов).

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

Устарел начиная с версии 3.9; будет удалён в версии 3.17.

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.

Устарел начиная с версии 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.

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

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

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

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

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

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

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

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

Изменено в версии 3.13: Теперь параметр SendType имеет значение по умолчанию.

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.

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

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

Изменено в версии 3.13: Добавлены значения по умолчанию для типов отправки и возврата.

class typing.Hashable

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

Устарело начиная с версии 3.12: Вместо этого используйте непосредственно 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.

Устарело начиная с версии 3.12: Вместо этого используйте непосредственно collections.abc.Sized.

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

class typing.ContextManager(Generic[T_co, ExitT_co])

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

Первый параметр типа, T_co, обозначает тип, возвращаемый методом __enter__(). Необязательный второй параметр типа, ExitT_co, значение которого по умолчанию — bool | None, обозначает тип, возвращаемый методом __exit__().

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

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

Изменено в версии 3.13: Добавлен необязательный второй параметр типа, ExitT_co.

class typing.AsyncContextManager(Generic[T_co, AExitT_co])

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

Первый параметр типа, T_co, обозначает тип, возвращаемый методом __aenter__(). Необязательный второй параметр типа, AExitT_co, значение которого по умолчанию — bool | None, обозначает тип, возвращаемый методом __aexit__().

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

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

Изменено в версии 3.13: Добавлен необязательный второй параметр типа, AExitT_co.

Сроки устаревания основных возможностей

Некоторые возможности в typing объявлены устаревшими и могут быть удалены в будущей версии Python. Для удобства в следующей таблице приведены основные сведения об устаревших возможностях. Эти сведения могут измениться; в таблице перечислены не все устаревшие возможности.

Возможность

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

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

PEP/issue

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

3.9

Не определено (подробности см. в разделе Устаревшие псевдонимы)

PEP 585

typing.ByteString

3.9

3.17

gh-91896

typing.Text

3.11

Не определено

gh-92332

typing.Hashable и typing.Sized

3.12

Не определено

gh-94309

typing.TypeAlias

3.12

Не определено

PEP 695

@typing.no_type_check_decorator

3.13

3.15

gh-106309

typing.AnyStr

3.13

3.18

gh-105578

© 2001 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.14/library/typing.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API