typing
— Поддержка подсказок по типу текста¶
Добавлено в версии 3.5.
Исходный код: Lib/typing.py
Примечание
Среда выполнения Python не использует аннотации к функциям и типам переменных. Они могут использоваться сторонними инструментами, такими как type checkers, IDE, линтеры и т.д.
Этот модуль обеспечивает поддержку подсказок по набору текста во время выполнения. Исходную спецификацию системы ввода смотрите в разделе PEP 484. Упрощенное введение в подсказки по набору текста смотрите в разделе PEP 483.
Приведенная ниже функция принимает и возвращает строку и аннотируется следующим образом:
def greeting(name: str) -> str:
return 'Hello ' + name
В функции greeting
ожидается, что аргумент name
будет иметь тип str
, а возвращаемый тип str
. В качестве аргументов принимаются подтипы.
В модуль typing
часто добавляются новые функции. Пакет typing_extensions обеспечивает перенос этих новых функций в более старые версии Python.
Краткое описание устаревших функций и график их выхода из строя приведены в разделе Deprecation Timeline of Major Features.
См.также
- «Typing cheat sheet»
Краткий обзор подсказок по вводу текста (размещен в mypy docs)
- Раздел «Справочник по системе типов» в the mypy docs
Система ввода в Python стандартизирована с помощью Pips, поэтому эта ссылка должна в целом применяться к большинству средств проверки типов в Python. (Некоторые части все еще могут быть специфичны для mypy).
- «Static Typing with Python»
Не зависящая от проверки набора текста документация, написанная сообществом, в которой подробно описываются функции системы ввода, полезные инструменты, связанные с набором текста, и рекомендации по набору текста.
Соответствующие PEPS¶
С момента первоначального появления подсказок о типах в PEP 484 и PEP 483 в ряде пунктов была изменена и усовершенствована структура Python для аннотаций типов:
The full list of PEPs
- PEP 544: Протоколы: Структурный подтип (статическая утиная типизация)
Представляем
Protocol
и декоратор@runtime_checkable
- PEP 585: Введите Общие Подсказки В Стандартных Коллекциях
Представляем
types.GenericAlias
и возможность использовать стандартные библиотечные классы как generic types
- PEP 604: Разрешить запись типов объединений в виде
X | Y
*Представляем *
types.UnionType
и возможность использовать двоичный оператор or|
для обозначения union of types
- PEP 604: Разрешить запись типов объединений в виде
- PEP 612: Переменные спецификации параметров
Представляем
ParamSpec
иConcatenate
- PEP 646: Вариативные обобщения
Представляем
TypeVarTuple
- PEP 655: Помечает отдельные элементы Type dict как необходимые или потенциально отсутствующие
Представляем
Required
иNotRequired
- PEP 675: Произвольный строковый тип литерала
Представляем
LiteralString
- PEP 681: Преобразование класса данных
Представляем декоратора
@dataclass_transform
Псевдонимы типов¶
Псевдоним типа определяется путем присвоения псевдониму типа. В этом примере Vector
и list[float]
будут рассматриваться как взаимозаменяемые синонимы:
Vector = list[float]
def scale(scalar: float, vector: Vector) -> Vector:
return [scalar * num for num in vector]
# passes type checking; a list of floats qualifies as a Vector.
new_vector = scale(2.0, [1.0, -4.2, 5.4])
Псевдонимы типов полезны для упрощения сигнатур сложных типов. Например:
from collections.abc import Sequence
ConnectionOptions = dict[str, str]
Address = tuple[str, int]
Server = tuple[Address, ConnectionOptions]
def broadcast_message(message: str, servers: Sequence[Server]) -> None:
...
# The static type checker will treat the previous type signature as
# being exactly equivalent to this one.
def broadcast_message(
message: str,
servers: Sequence[tuple[tuple[str, int], dict[str, str]]]) -> None:
...
Псевдонимы типов могут быть помечены знаком TypeAlias
, чтобы четко указать, что оператор является объявлением псевдонима типа, а не обычным назначением переменной:
from typing import TypeAlias
Vector: TypeAlias = list[float]
Новый тип¶
Используйте помощник NewType
для создания различных типов:
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)
Вы по-прежнему можете выполнять все операции int
с переменной типа UserId
, но результат всегда будет иметь тип int
. Это позволяет вам вводить UserId
везде, где можно было бы ожидать int
, но не позволит вам случайно создать UserId
недопустимым образом:
# 'output' is of type 'int', not 'UserId'
output = UserId(23413) + UserId(54341)
Обратите внимание, что эти проверки выполняются только средством проверки статического типа. Во время выполнения оператор Derived = NewType('Derived', Base)
создаст Derived
вызываемый объект, который немедленно вернет любой параметр, который вы ему передадите. Это означает, что выражение Derived(some_value)
не создает новый класс и не приводит к большим накладным расходам, чем при обычном вызове функции.
Точнее, выражение some_value is Derived(some_value)
всегда истинно во время выполнения.
Недопустимо создавать подтип Derived
:
from typing import NewType
UserId = NewType('UserId', int)
# Fails at runtime and does not pass type checking
class AdminUserId(UserId): pass
Однако можно создать NewType
на основе «производного» NewType
:
from typing import NewType
UserId = NewType('UserId', int)
ProUserId = NewType('ProUserId', UserId)
и проверка типа для ProUserId
будет работать так, как ожидалось.
Смотрите PEP 484 для получения более подробной информации.
Примечание
Напомним, что использование псевдонима типа объявляет два типа эквивалентными друг другу. Выполнение Alias = Original
приведет к тому, что средство статической проверки типов будет рассматривать Alias
как в точности эквивалентное Original
во всех случаях. Это полезно, когда вы хотите упростить подписи сложных типов.
Напротив, NewType
объявляет один тип подтипом другого. Выполнение Derived = NewType('Derived', Original)
приведет к тому, что средство проверки статического типа будет рассматривать Derived
как подкласс из Original
, что означает, что значение типа Original
не может использоваться там, где значение типа <ожидается Derived
. Это полезно, если вы хотите предотвратить логические ошибки с минимальными затратами времени выполнения.
Добавлено в версии 3.5.2.
Изменено в версии 3.10: NewType
теперь является классом, а не функцией. В результате возникают некоторые дополнительные затраты времени выполнения при вызове NewType
из обычной функции.
Изменено в версии 3.11: Производительность вызова NewType
была восстановлена до прежнего уровня в Python 3.9.
Аннотирование вызываемых объектов¶
Функции или другие объекты callable могут быть аннотированы с помощью 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
Синтаксис subscription всегда должен использоваться только с двумя значениями: списком аргументов и типом возвращаемого значения. Список аргументов должен быть списком типов, символом ParamSpec
, Concatenate
, или многоточием. Возвращаемый тип должен быть одного типа.
Если в качестве списка аргументов указано многоточие ...
, это указывает на то, что был бы приемлем вызываемый объект с любым произвольным списком параметров:
def concat(x: str, y: str) -> str:
return x + y
x: Callable[..., str]
x = str # OK
x = concat # Also OK
Callable
не может выражать сложные сигнатуры, такие как функции, которые принимают переменное число аргументов, overloaded functions или функции, которые имеют параметры только для ключевых слов. Однако эти сигнатуры могут быть выражены путем определения класса Protocol
с помощью метода __call__()
:
from collections.abc import Iterable
from typing import Protocol
class Combiner(Protocol):
def __call__(self, *vals: bytes, maxlen: int | None = None) -> list[bytes]: ...
def batch_proc(data: Iterable[bytes], cb_results: Combiner) -> bytes:
for item in data:
...
def good_cb(*vals: bytes, maxlen: int | None = None) -> list[bytes]:
...
def bad_cb(*vals: bytes, maxitems: int | None) -> list[bytes]:
...
batch_proc([], good_cb) # OK
batch_proc([], bad_cb) # Error! Argument 2 has incompatible type because of
# different name and kind in the callback
Вызываемые объекты, которые принимают другие вызываемые объекты в качестве аргументов, могут указывать на то, что их типы параметров зависят друг от друга, используя ParamSpec
. Кроме того, если этот вызываемый объект добавляет или удаляет аргументы из других вызываемых объектов, может быть использован оператор Concatenate
. Они имеют вид Callable[ParamSpecVariable, ReturnType]
и Callable[Concatenate[Arg1Type, Arg2Type, ..., ParamSpecVariable], ReturnType]
соответственно.
Изменено в версии 3.10: Callable
теперь поддерживает ParamSpec
и Concatenate
. Более подробную информацию смотрите в PEP 612.
См.также
В документации для ParamSpec
и Concatenate
приведены примеры использования в Callable
.
Дженерики¶
Поскольку информация о типе объектов, хранящихся в контейнерах, не может быть статически выведена общим способом, многие классы контейнеров в стандартной библиотеке поддерживают подписку для обозначения ожидаемых типов элементов контейнера.
from collections.abc import Mapping, Sequence
class Employee: ...
# Sequence[Employee] indicates that all elements in the sequence
# must be instances of "Employee".
# Mapping[str, str] indicates that all keys and all values in the mapping
# must be strings.
def notify_by_email(employees: Sequence[Employee],
overrides: Mapping[str, str]) -> None: ...
Обобщенные значения могут быть параметризованы с помощью фабрики, доступной при вводе текста, которая называется TypeVar
.
from collections.abc import Sequence
from typing import TypeVar
T = TypeVar('T') # Declare type variable "T"
def first(l: Sequence[T]) -> T: # Function is generic over the TypeVar "T"
return l[0]
Кортежи аннотаций¶
Для большинства контейнеров в Python система ввода предполагает, что все элементы в контейнере будут одного типа. Например:
from collections.abc import Mapping
# Type checker will infer that all elements in ``x`` are meant to be ints
x: list[int] = []
# Type checker error: ``list`` only accepts a single type argument:
y: list[int, str] = [1, 'foo']
# Type checker will infer that all keys in ``z`` are meant to be strings,
# and that all values in ``z`` are meant to be either strings or ints
z: Mapping[str, str | int] = {}
list
принимает только один аргумент типа, поэтому средство проверки типов выдало бы ошибку при задании y
, приведенном выше. Аналогично, Mapping
принимает только два аргумента типа: первый указывает тип ключей, а второй - тип значений.
Однако, в отличие от большинства других контейнеров Python, в идиоматическом коде Python кортежи часто содержат элементы, которые не все относятся к одному типу. По этой причине в системе ввода Python для кортежей используется специальный регистр. tuple
принимает любое количество аргументов типа:
# OK: ``x`` is assigned to a tuple of length 1 where the sole element is an int
x: tuple[int] = (5,)
# OK: ``y`` is assigned to a tuple of length 2;
# element 1 is an int, element 2 is a str
y: tuple[int, str] = (5, "foo")
# Error: the type annotation indicates a tuple of length 1,
# but ``z`` has been assigned to a tuple of length 3
z: tuple[int] = (1, 2, 3)
Для обозначения кортежа, который может быть любой длины и в котором все элементы имеют один и тот же тип T
, используйте tuple[T, ...]
. Для обозначения пустого кортежа используйте tuple[()]
. Использование простого tuple
в качестве аннотации эквивалентно использованию tuple[Any, ...]
:
x: tuple[int, ...] = (1, 2)
# These reassignments are OK: ``tuple[int, ...]`` indicates x can be of any length
x = (1, 2, 3)
x = ()
# This reassignment is an error: all elements in ``x`` must be ints
x = ("foo", "bar")
# ``y`` can only ever be assigned to an empty tuple
y: tuple[()] = ()
z: tuple = ("foo", "bar")
# These reassignments are OK: plain ``tuple`` is equivalent to ``tuple[Any, ...]``
z = (1, 2, 3)
z = ()
Тип объектов класса¶
Переменная, помеченная как C
, может принимать значение типа C
. Напротив, переменная, помеченная как type[C]
(или typing.Type[C]
), может принимать значения, которые сами по себе являются классами - в частности, она будет принимать class object из 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
, type variables, и объединения любого из этих типов. Например:
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
, которое является корнем metaclass hierarchy в Python.
Определяемые пользователем универсальные типы¶
Определяемый пользователем класс может быть определен как универсальный класс.
from typing import TypeVar, Generic
from logging import Logger
T = TypeVar('T')
class LoggedVar(Generic[T]):
def __init__(self, value: T, name: str, logger: Logger) -> None:
self.name = name
self.logger = logger
self.value = value
def set(self, new: T) -> None:
self.log('Set ' + repr(self.value))
self.value = new
def get(self) -> T:
self.log('Get ' + repr(self.value))
return self.value
def log(self, message: str) -> None:
self.logger.info('%s: %s', self.name, message)
Generic[T]
в качестве базового класса определяет, что класс LoggedVar
принимает единственный параметр типа T
. Это также делает T
допустимым в качестве типа в теле класса.
Базовый класс Generic
определяет __class_getitem__()
таким образом, что LoggedVar[T]
является допустимым типом:
from collections.abc import Iterable
def zero_all_vars(vars: Iterable[LoggedVar[int]]) -> None:
for var in vars:
var.set(0)
Общий тип может содержать любое количество переменных типа. Все варианты TypeVar
допустимы в качестве параметров для общего типа:
from typing import TypeVar, Generic, Sequence
T = TypeVar('T', contravariant=True)
B = TypeVar('B', bound=Sequence[bytes], covariant=True)
S = TypeVar('S', int, str)
class WeirdTrio(Generic[T, B, S]):
...
Каждый аргумент переменной типа Generic
должен быть разным. Таким образом, это недопустимо:
from typing import TypeVar, Generic
...
T = TypeVar('T')
class Pair(Generic[T, T]): # INVALID
...
Вы можете использовать множественное наследование с помощью Generic
:
from collections.abc import Sized
from typing import TypeVar, Generic
T = TypeVar('T')
class LinkedList(Sized, Generic[T]):
...
При наследовании от универсальных классов некоторые параметры типа могут быть исправлены:
from collections.abc import Mapping
from typing import TypeVar
T = TypeVar('T')
class MyDict(Mapping[str, T]):
...
В этом случае MyDict
имеет единственный параметр T
.
Использование универсального класса без указания параметров типа предполагает Any
для каждой позиции. В следующем примере MyIterable
не является универсальным, а неявно наследуется от Iterable[Any]
:
from collections.abc import Iterable
class MyIterable(Iterable): # Same as Iterable[Any]
...
Также поддерживаются псевдонимы универсальных типов, определяемые пользователем. Примеры:
from collections.abc import Iterable
from typing import TypeVar
S = TypeVar('S')
Response = Iterable[S] | int
# Return type here is same as Iterable[str] | int
def response(query: str) -> Response[str]:
...
T = TypeVar('T', int, float, complex)
Vec = Iterable[tuple[T, T]]
def inproduct(v: Vec[T]) -> T: # Same as Iterable[tuple[T, T]]
return sum(x*y for x, y in v)
Изменено в версии 3.7: Generic
больше не имеет пользовательского метакласса.
Пользовательские обобщенные выражения для параметров также поддерживаются с помощью переменных спецификации параметров в форме Generic[P]
. Поведение соответствует описанным выше переменным типа, поскольку переменные спецификации параметров обрабатываются модулем ввода как переменные специализированного типа. Единственным исключением из этого правила является то, что список типов может быть использован для замены ParamSpec
:
>>> from typing import Generic, ParamSpec, TypeVar
>>> T = TypeVar('T')
>>> P = ParamSpec('P')
>>> class Z(Generic[T, P]): ...
...
>>> Z[int, [dict, float]]
__main__.Z[int, (<class 'dict'>, <class 'float'>)]
Кроме того, универсальное приложение, имеющее только одну переменную спецификации параметров, будет принимать списки параметров в формах X[[Type1, Type2, ...]]
, а также X[Type1, Type2, ...]
по эстетическим соображениям. Внутренне последнее преобразуется в первое, поэтому следующие значения эквивалентны:
>>> class X(Generic[P]): ...
...
>>> X[int, str]
__main__.X[(<class 'int'>, <class 'str'>)]
>>> X[[int, str]]
__main__.X[(<class 'int'>, <class 'str'>)]
Обратите внимание, что в некоторых случаях дженерики с ParamSpec
могут не иметь корректного __parameters__
после замены, поскольку они предназначены в первую очередь для статической проверки типов.
Изменено в версии 3.10: Generic
теперь можно параметризовать с помощью выражений параметров. Более подробную информацию смотрите в ParamSpec
и PEP 612.
Пользовательский универсальный класс может иметь ABC в качестве базовых классов без конфликта метаклассов. Универсальные метаклассы не поддерживаются. Результат параметризации обобщенных значений кэшируется, и большинство типов в модуле ввода являются hashable и сопоставимы на предмет равенства.
Тип Any
¶
Особым типом типа является Any
. Статическая проверка типов будет рассматривать каждый тип как совместимый с Any
и Any
как совместимый с каждым типом.
Это означает, что можно выполнить любую операцию или вызвать метод для значения типа Any
и присвоить его любой переменной:
from typing import Any
a: Any = None
a = [] # OK
a = 2 # OK
s: str = ''
s = a # OK
def foo(item: Any) -> int:
# Passes type checking; 'item' could be any type,
# and that type might have a 'bar' method
item.bar()
...
Обратите внимание, что проверка типа не выполняется при присвоении значения типа Any
более точному типу. Например, средство статической проверки типов не сообщило об ошибке при присвоении a
s
, хотя s
было объявлено как тип str
и получено значение int
значение во время выполнения!
Кроме того, все функции без возвращаемого типа или типов параметров по умолчанию будут неявно использовать Any
:
def legacy_parser(text):
...
return data
# A static type checker will treat the above
# as having the same signature as:
def legacy_parser(text: Any) -> Any:
...
return data
Такое поведение позволяет использовать Any
в качестве аварийного выхода, когда вам нужно смешать динамически и статически типизированный код.
Сравните поведение Any
с поведением object
. Аналогично Any
, каждый тип является подтипом object
. Однако, в отличие от Any
, обратное неверно: object
не является подтипом любого другого типа.
Это означает, что когда тип значения равен object
, средство проверки типов отклоняет почти все операции с ним, а присвоение его переменной (или использование ее в качестве возвращаемого значения) более специализированного типа является ошибкой типа. Например:
def hash_a(item: object) -> int:
# Fails type checking; an object does not have a 'magic' method.
item.magic()
...
def hash_b(item: Any) -> int:
# Passes type checking
item.magic()
...
# Passes type checking, since ints and strs are subclasses of object
hash_a(42)
hash_a("foo")
# Passes type checking, since Any is compatible with all types
hash_b(42)
hash_b("foo")
Используйте object
, чтобы указать, что значение может быть любого типа в соответствии с правилами типизации. Используйте Any
, чтобы указать, что значение вводится динамически.
Номинальный и структурный подтипы¶
Изначально PEP 484 определял систему статических типов Python как использующую номинальный подтип. Это означает, что класс A
разрешен там, где класс B
ожидается тогда и только тогда, когда A
является подклассом B
.
Ранее это требование также применялось к абстрактным базовым классам, таким как Iterable
. Проблема с этим подходом заключается в том, что класс должен был быть явно помечен для их поддержки, что не соответствует python и отличается от того, что обычно делается в идиоматическом динамически типизированном коде на Python. Например, это соответствует PEP 484:
from collections.abc import Sized, Iterable, Iterator
class Bucket(Sized, Iterable[int]):
...
def __len__(self) -> int: ...
def __iter__(self) -> Iterator[int]: ...
PEP 544 позволяет решить эту проблему, позволяя пользователям писать приведенный выше код без явных базовых классов в определении класса, позволяя Bucket
неявно рассматривать как подтип как Sized
, так и Iterable[int]
с помощью статических средств проверки типов. Это известно как структурный подтипинг (или статическая утиная типизация).:
from collections.abc import Iterator, Iterable
class Bucket: # Note: no base classes
...
def __len__(self) -> int: ...
def __iter__(self) -> Iterator[int]: ...
def collect(items: Iterable[int]) -> int: ...
result = collect(Bucket()) # Passes type check
Более того, создав специальный подкласс Protocol
, пользователь может определять новые пользовательские протоколы, чтобы в полной мере использовать структурные подтипы (см. примеры ниже).
Содержимое модуля¶
Модуль typing
определяет следующие классы, функции и декораторы.
Специальные примитивы набора текста¶
Специальные типы¶
Их можно использовать в качестве типов в аннотациях. Они не поддерживают подписку с использованием []
.
- typing.Any¶
Специальный тип, указывающий на неограниченный тип.
Изменено в версии 3.11:
Any
теперь можно использовать в качестве базового класса. Это может быть полезно для предотвращения ошибок проверки типов в классах, которые могут вводить текст в любом месте или являются высокодинамичными.
- typing.AnyStr¶
-
Определение:
AnyStr = TypeVar('AnyStr', str, bytes)
AnyStr
предназначен для функций, которые могут принимать аргументыstr
илиbytes
, но не могут допускать их смешивания.Например:
def concat(a: AnyStr, b: AnyStr) -> AnyStr: return a + b concat("foo", "bar") # OK, output has type 'str' concat(b"foo", b"bar") # OK, output has type 'bytes' concat("foo", b"bar") # Error, cannot mix str and bytes
Обратите внимание, что, несмотря на свое название,
AnyStr
не имеет ничего общего с типомAny
и не означает «любая строка». В частности,AnyStr
иstr | bytes
отличаются друг от друга и имеют разные варианты использования:# Invalid use of AnyStr: # The type variable is used only once in the function signature, # so cannot be "solved" by the type checker def greet_bad(cond: bool) -> AnyStr: return "hi there!" if cond else b"greetings!" # The better way of annotating this function: def greet_proper(cond: bool) -> str | bytes: return "hi there!" if cond else b"greetings!"
- typing.LiteralString¶
Специальный тип, который включает в себя только литеральные строки.
Любой строковый литерал совместим с
LiteralString
, как и другойLiteralString
. Однако объект, введенный просто какstr
, таковым не является. Строка, созданная путем объединения объектов, набранных вLiteralString
, также допустима в качествеLiteralString
.Пример:
def run_query(sql: LiteralString) -> None: ... def caller(arbitrary_string: str, literal_string: LiteralString) -> None: run_query("SELECT * FROM students") # OK run_query(literal_string) # OK run_query("SELECT * FROM " + literal_string) # OK run_query(arbitrary_string) # type checker error run_query( # type checker error f"SELECT * FROM students WHERE name = {arbitrary_string}" )
LiteralString
полезно для уязвимых API, где произвольные пользовательские строки могут создавать проблемы. Например, два приведенных выше случая, которые приводят к ошибкам проверки типов, могут быть уязвимы для атаки с помощью SQL-инъекции.Смотрите PEP 675 для получения более подробной информации.
Добавлено в версии 3.11.
- typing.Never¶
bottom type - тип, у которого нет членов.
Это может быть использовано для определения функции, которая никогда не должна вызываться, или функции, которая никогда не возвращает результат:
from typing import Never def never_call_me(arg: Never) -> None: pass def int_or_str(arg: int | str) -> None: never_call_me(arg) # type checker error match arg: case int(): print("It's an int") case str(): print("It's a str") case _: never_call_me(arg) # OK, arg is of type Never
Добавлено в версии 3.11: В старых версиях Python
NoReturn
может использоваться для выражения той же концепции.Never
был добавлен, чтобы сделать предполагаемый смысл более явным.
- typing.NoReturn¶
Специальный тип, указывающий на то, что функция никогда не возвращает результат.
Например:
from typing import NoReturn def stop() -> NoReturn: raise RuntimeError('no way')
NoReturn
также может использоваться как bottom type, тип, который не имеет значений. Начиная с версии Python 3.11, для этой концепции следует использовать типNever
. Средства проверки типов должны относиться к этим двум элементам одинаково.Добавлено в версии 3.6.2.
- typing.Self¶
Специальный тип для представления текущего закрытого класса.
Например:
from typing import Self, reveal_type class Foo: def return_self(self) -> Self: ... return self class SubclassOfFoo(Foo): pass reveal_type(Foo().return_self()) # Revealed type is "Foo" reveal_type(SubclassOfFoo().return_self()) # Revealed type is "SubclassOfFoo"
Эта аннотация семантически эквивалентна следующей, хотя и в более сжатой форме:
from typing import TypeVar Self = TypeVar("Self", bound="Foo") class Foo: def return_self(self: Self) -> Self: ... return self
В общем, если что-то возвращает
self
, как в приведенных выше примерах, вы должны использоватьSelf
в качестве возвращаемой аннотации. Если быFoo.return_self
был помечен как возвращающий"Foo"
, то средство проверки типов определило бы, что объект, возвращенный изSubclassOfFoo.return_self
, имеет типFoo
, а неSubclassOfFoo
.Другие распространенные варианты использования включают:
classmethod
, которые используются в качестве альтернативных конструкторов и возвращают экземпляры параметраcls
.Аннотирование метода
__enter__()
, который возвращает self.
Вы не должны использовать
Self
в качестве возвращаемой аннотации, если метод не гарантирует возврат экземпляра подкласса, когда класс является подклассифицированным:class Eggs: # Self would be an incorrect return annotation here, # as the object returned is always an instance of Eggs, # even in subclasses def returns_eggs(self) -> "Eggs": return Eggs()
Смотрите PEP 673 для получения более подробной информации.
Добавлено в версии 3.11.
- typing.TypeAlias¶
Специальная аннотация для явного объявления type alias.
Например:
from typing import TypeAlias Factors: TypeAlias = list[int]
TypeAlias
особенно полезно для аннотирования псевдонимов, в которых используются прямые ссылки, поскольку специалистам по проверке типов может быть трудно отличить их от обычных назначений переменных:from typing import Generic, TypeAlias, TypeVar T = TypeVar("T") # "Box" does not exist yet, # so we have to use quotes for the forward reference. # Using ``TypeAlias`` tells the type checker that this is a type alias declaration, # not a variable assignment to a string. BoxOfStrings: TypeAlias = "Box[str]" class Box(Generic[T]): @classmethod def make_box_of_strings(cls) -> BoxOfStrings: ...
Смотрите PEP 613 для получения более подробной информации.
Добавлено в версии 3.10.
Специальные формы¶
Их можно использовать в качестве типов в аннотациях. Все они поддерживают подписку с использованием []
, но у каждого свой уникальный синтаксис.
- typing.Union¶
Тип объединения;
Union[X, Y]
эквивалентноX | Y
и означает либо X, либо Y.Чтобы определить объединение, используйте, например,
Union[int, str]
или сокращениеint | str
. Рекомендуется использовать это сокращение. Подробности:Аргументы должны быть типами, и их должен быть хотя бы один.
Объединения союзов сглаживаются, например:
Union[Union[int, str], float] == Union[int, str, float]
Объединения одного аргумента исчезают, например:
Union[int] == int # The constructor actually returns int
Избыточные аргументы пропускаются, например:
Union[int, str, int] == Union[int, str] == int | str
При сравнении объединений порядок аргументов игнорируется, например:
Union[int, str] == Union[str, int]
Вы не можете создать подкласс или экземпляр
Union
.Вы не можете написать
Union[X][Y]
.
Изменено в версии 3.7: Не удаляйте явные подклассы из объединений во время выполнения.
Изменено в версии 3.10: Союзы теперь можно записывать как
X | Y
. Смотрите union type expressions.
- 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: Необязательный теперь может быть записан как
X | None
. Смотрите union type expressions.
- typing.Concatenate¶
Специальная форма для аннотирования функций более высокого порядка.
Concatenate
может использоваться в сочетании с Callable иParamSpec
для аннотирования вызываемого объекта более высокого порядка, который добавляет, удаляет или преобразует параметры другого вызываемого объекта. Используется в формеConcatenate[Arg1Type, Arg2Type, ..., ParamSpecVariable]
.Concatenate
в настоящее время допустимо только при использовании в качестве первого аргумента для Callable. Последним параметромConcatenate
должен быть знакParamSpec
или многоточие (...
).Например, чтобы аннотировать декоратор
with_lock
, который предоставляетthreading.Lock
для оформленной функции, можно использоватьConcatenate
, чтобы указать, чтоwith_lock
ожидает вызываемый объект, который принимаетLock
в качестве первого аргумента и возвращает вызываемый объект с другой сигнатурой типа. В этом случаеParamSpec
указывает на то, что возвращаемые типы вызываемых параметров зависят от типов параметров вызываемого объекта, передаваемых в:from collections.abc import Callable from threading import Lock from typing import Concatenate, ParamSpec, TypeVar P = ParamSpec('P') R = TypeVar('R') # Use this lock to ensure that only one thread is executing a function # at any time. my_lock = Lock() def with_lock(f: Callable[Concatenate[Lock, P], R]) -> Callable[P, R]: '''A type-safe decorator which provides a lock.''' def inner(*args: P.args, **kwargs: P.kwargs) -> R: # Provide the lock as the first argument. return f(my_lock, *args, **kwargs) return inner @with_lock def sum_threadsafe(lock: Lock, numbers: list[float]) -> float: '''Add a list of numbers together in a thread-safe manner.''' with lock: return sum(numbers) # We don't need to pass in the lock ourselves thanks to the decorator. sum_threadsafe([1.1, 2.2, 3.3])
Добавлено в версии 3.10.
См.также
PEP 612 – Переменные спецификации параметров (PEP, который ввел
ParamSpec
иConcatenate
)
- typing.Literal¶
Специальная форма ввода для определения «литеральных типов».
Literal
может использоваться для указания средствам проверки типов, что аннотированный объект имеет значение, эквивалентное одному из предоставленных литералов.Например:
def validate_simple(data: Any) -> Literal[True]: # always returns True ... Mode: TypeAlias = Literal['r', 'rb', 'w', 'wb'] def open_helper(file: str, mode: Mode) -> str: ... open_helper('/some/path', 'r') # Passes type check open_helper('/other/path', 'typo') # Error in type checker
Literal[...]
не может быть разделен на подклассы. Во время выполнения допускается использование произвольного значения в качестве аргумента типаLiteral[...]
, но средства проверки типов могут накладывать ограничения. Более подробную информацию о литеральных типах см. в разделе PEP 586.Добавлено в версии 3.8.
- typing.ClassVar¶
Специальная конструкция типа для обозначения переменных класса.
Как указано в PEP 526, аннотация к переменной, заключенная в ClassVar, указывает на то, что данный атрибут предназначен для использования в качестве переменной класса и не должен устанавливаться в экземплярах этого класса. Использование:
class Starship: stats: ClassVar[dict[str, int]] = {} # class variable damage: int = 10 # instance variable
ClassVar
принимает только типы и не может быть дополнительно подписан.ClassVar
сам по себе не является классом и не должен использоваться сisinstance()
илиissubclass()
.ClassVar
не изменяет поведение Python во время выполнения, но может использоваться сторонними средствами проверки типов. Например, средство проверки типов может отметить следующий код как ошибку:enterprise_d = Starship(3000) enterprise_d.stats = {} # Error, setting class variable on instance Starship.stats = {} # This is OK
Добавлено в версии 3.5.3.
- typing.Final¶
Специальная конструкция ввода для указания окончательных имен для проверки типов.
Конечные имена не могут быть переназначены ни в одной области. Конечные имена, объявленные в областях классов, не могут быть переопределены в подклассах.
Например:
MAX_SIZE: Final = 9000 MAX_SIZE += 1 # Error reported by type checker class Connection: TIMEOUT: Final[int] = 10 class FastConnector(Connection): TIMEOUT = 1 # Error reported by type checker
Проверка этих свойств во время выполнения не выполняется. Более подробную информацию смотрите в разделе PEP 591.
Добавлено в версии 3.8.
- typing.Required¶
Специальная конструкция ввода для обозначения клавиши
TypedDict
по мере необходимости.В основном это полезно для ввода
total=False
. Более подробную информацию смотрите вTypedDict
и PEP 655.Добавлено в версии 3.11.
- typing.NotRequired¶
Специальная конструкция ввода для обозначения клавиши
TypedDict
как потенциально отсутствующей.Смотрите
TypedDict
и PEP 655 для получения более подробной информации.Добавлено в версии 3.11.
- typing.Annotated¶
Специальная форма ввода для добавления метаданных, зависящих от контекста, в аннотацию.
Добавьте метаданные
x
к заданному типуT
, используя аннотациюAnnotated[T, x]
. Метаданные, добавленные с помощьюAnnotated
, могут использоваться инструментами статического анализа или во время выполнения. Во время выполнения метаданные сохраняются в атрибуте__metadata__
.Если библиотека или инструмент обнаруживает аннотацию
Annotated[T, x]
и не имеет специальной логики для метаданных, она должна игнорировать метаданные и просто обрабатывать аннотацию какT
. Таким образом,Annotated
может быть полезен для кода, который хочет использовать аннотации для целей, не связанных с системой статической типизации Python.Использование
Annotated[T, x]
в качестве аннотации по-прежнему допускает статическую проверку типовT
, поскольку средства проверки типов просто игнорируют метаданныеx
. Таким образом,Annotated
отличается от@no_type_check
декоратора, который также может использоваться для добавления аннотаций за пределами системы ввода, но полностью отключает проверку типов для функции или класса.Ответственность за интерпретацию метаданных лежит на инструменте или библиотеке, которые обнаруживают аннотацию
Annotated
. Инструмент или библиотека, обнаруживающие типAnnotated
, могут сканировать элементы метаданных, чтобы определить, представляют ли они интерес (например, используяisinstance()
).- Annotated[<type>, <metadata>]
Вот пример того, как вы могли бы использовать
Annotated
для добавления метаданных к аннотациям типов, если бы вы проводили анализ диапазона:@dataclass class ValueRange: lo: int hi: int T1 = Annotated[int, ValueRange(-10, 5)] T2 = Annotated[T1, ValueRange(-20, 3)]
Подробные сведения о синтаксисе:
Первый аргумент
Annotated
должен иметь допустимый типМожет быть предоставлено несколько элементов метаданных (
Annotated
поддерживает переменные аргументы).:@dataclass class ctype: kind: str Annotated[int, ValueRange(3, 10), ctype("char")]
Инструмент, использующий аннотации, должен решить, разрешено ли клиенту добавлять несколько элементов метаданных в одну аннотацию и как объединить эти аннотации.
Annotated
должен быть подписан как минимум двумя аргументами (Annotated[int]
недопустимо)Порядок элементов метаданных сохраняется и имеет значение для проверки на равенство:
assert Annotated[int, ValueRange(3, 10), ctype("char")] != Annotated[ int, ctype("char"), ValueRange(3, 10) ]
Вложенные типы
Annotated
сглаживаются. Порядок расположения элементов метаданных начинается с самой внутренней аннотации:assert Annotated[Annotated[int, ValueRange(3, 10)], ctype("char")] == Annotated[ int, ValueRange(3, 10), ctype("char") ]
Дублированные элементы метаданных не удаляются:
assert Annotated[int, ValueRange(3, 10)] != Annotated[ int, ValueRange(3, 10), ValueRange(3, 10) ]
Annotated
может использоваться с вложенными и универсальными псевдонимами:@dataclass class MaxLen: value: int T = TypeVar("T") Vec: TypeAlias = Annotated[list[tuple[T, T]], MaxLen(10)] assert Vec[int] == Annotated[list[tuple[int, int]], MaxLen(10)]
Annotated
не может использоваться с распакованнымTypeVarTuple
:Variadic: TypeAlias = Annotated[*Ts, Ann1] # NOT valid
Это было бы эквивалентно:
Annotated[T1, T2, T3, ..., Ann1]
где
T1
,T2
, и т.д. - этоTypeVars
. Это было бы недопустимо: в Annotated должен быть передан только один тип.По умолчанию
get_type_hints()
удаляет метаданные из аннотаций. Введитеinclude_extras=True
, чтобы сохранить метаданные:>>> from typing import Annotated, get_type_hints >>> def func(x: Annotated[int, "metadata"]) -> None: pass ... >>> get_type_hints(func) {'x': <class 'int'>, 'return': <class 'NoneType'>} >>> get_type_hints(func, include_extras=True) {'x': typing.Annotated[int, 'metadata'], 'return': <class 'NoneType'>}
Во время выполнения метаданные, связанные с типом
Annotated
, могут быть получены с помощью атрибута__metadata__
:>>> from typing import Annotated >>> X = Annotated[int, "very", "important", "metadata"] >>> X typing.Annotated[int, 'very', 'important', 'metadata'] >>> X.__metadata__ ('very', 'important', 'metadata')
См.также
- PEP 593 - Гибкие аннотации к функциям и переменным
PEP, вводящий
Annotated
в стандартную библиотеку.
Добавлено в версии 3.9.
- typing.TypeGuard¶
Специальная конструкция ввода для обозначения определяемых пользователем функций защиты типов.
TypeGuard
может использоваться для указания типа возвращаемого значения пользовательской функции type guard.TypeGuard
принимает только один аргумент типа. Во время выполнения функции, помеченные таким образом, должны возвращать логическое значение.TypeGuard
предназначен для использования в интересах сужения типов - метода, используемого средствами статической проверки типов для определения более точного типа выражения в потоке программного кода. Обычно сужение типов выполняется путем анализа потока условного кода и применения сужения к блоку кода. Условное выражение здесь иногда называют «защитой типа».:def is_str(val: str | float): # "isinstance" type guard if isinstance(val, str): # Type of ``val`` is narrowed to ``str`` ... else: # Else, type of ``val`` is narrowed to ``float``. ...
Иногда было бы удобно использовать пользовательскую логическую функцию в качестве средства защиты типов. Такая функция должна использовать
TypeGuard[...]
в качестве возвращаемого типа, чтобы предупредить об этом средства проверки статических типов.Использование
-> TypeGuard
сообщает программе проверки статического типа, что для данной функции:Возвращаемое значение является логическим.
Если возвращаемое значение равно
True
, то типом его аргумента является тип внутриTypeGuard
.
Например:
def is_str_list(val: list[object]) -> TypeGuard[list[str]]: '''Determines whether all objects in the list are strings''' return all(isinstance(x, str) for x in val) def func1(val: list[object]): if is_str_list(val): # Type of ``val`` is narrowed to ``list[str]``. print(" ".join(val)) else: # Type of ``val`` remains as ``list[object]``. print("Not a list of strings!")
Если
is_str_list
является методом класса или экземпляра, то тип вTypeGuard
соответствует типу второго параметра послеcls
илиself
.Короче говоря, форма
def foo(arg: TypeA) -> TypeGuard[TypeB]: ...
означает, что еслиfoo(arg)
возвращаетTrue
, тоarg
сужается сTypeA
доTypeB
.Примечание
TypeB
не обязательно должно быть более узкой формойTypeA
- это может быть даже более широкая форма. Основная причина заключается в том, чтобы разрешить такие вещи, как сужениеlist[object]
доlist[str]
, даже если последнее не является подтипом первого, посколькуlist
является инвариантным. Ответственность за написание типобезопасных средств защиты типов возлагается на пользователя.TypeGuard
также работает с переменными типа. Более подробную информацию смотрите в PEP 647.Добавлено в версии 3.10.
- typing.Unpack¶
Оператор ввода для концептуальной пометки объекта как распакованного.
Например, использование оператора распаковки
*
для type variable tuple эквивалентно использованиюUnpack
для обозначения переменной типа tuple как распакованной:Ts = TypeVarTuple('Ts') tup: tuple[*Ts] # Effectively does: tup: tuple[Unpack[Ts]]
Фактически,
Unpack
может использоваться взаимозаменяемо с*
в контексте типовtyping.TypeVarTuple
иbuiltins.tuple
. Вы можете увидеть, чтоUnpack
явно использовался в более старых версиях Python, где*
не мог использоваться в определенных местах:# In older versions of Python, TypeVarTuple and Unpack # are located in the `typing_extensions` backports package. from typing_extensions import TypeVarTuple, Unpack Ts = TypeVarTuple('Ts') tup: tuple[*Ts] # Syntax error on Python <= 3.10! tup: tuple[Unpack[Ts]] # Semantically equivalent, and backwards-compatible
Добавлено в версии 3.11.
Создание универсальных типов¶
Следующие классы не следует использовать непосредственно в качестве аннотаций. Их предполагаемое назначение - быть строительными блоками для создания универсальных типов.
- class typing.Generic¶
Абстрактный базовый класс для универсальных типов.
Универсальный тип обычно объявляется путем наследования от экземпляра этого класса с помощью одной или нескольких переменных типа. Например, универсальный тип отображения может быть определен как:
class Mapping(Generic[KT, VT]): def __getitem__(self, key: KT) -> VT: ... # Etc.
Затем этот класс можно использовать следующим образом:
X = TypeVar('X') Y = TypeVar('Y') def lookup_name(mapping: Mapping[X, Y], key: X, default: Y) -> Y: try: return mapping[key] except KeyError: return default
- class typing.TypeVar(name, *constraints, bound=None, covariant=False, contravariant=False)¶
Введите переменную.
Использование:
T = TypeVar('T') # Can be anything S = TypeVar('S', bound=str) # Can be any subtype of str A = TypeVar('A', str, bytes) # Must be exactly str or bytes
Переменные типа существуют в основном для статической проверки типов. Они служат параметрами для универсальных типов, а также для определения универсальных функций и псевдонимов типов. Дополнительную информацию о универсальных типах смотрите в разделе
Generic
. Универсальные функции работают следующим образом:def repeat(x: T, n: int) -> Sequence[T]: """Return a list containing n references to x.""" return [x]*n def print_capitalized(x: S) -> S: """Print x capitalized, and return x.""" print(x.capitalize()) return x def concatenate(x: A, y: A) -> A: """Add two strings or bytes objects together.""" return x + y
Обратите внимание, что переменные типа могут быть связаны, ограничены или ни тем, ни другим, но не могут быть одновременно связаны * и* ограничены.
Переменные типа могут быть помечены как ковариантные или контравариантные, передавая
covariant=True
илиcontravariant=True
. Более подробную информацию смотрите в разделе PEP 484. По умолчанию переменные типа являются инвариантными.Переменные связанного типа и переменные ограниченного типа имеют различную семантику в нескольких важных аспектах. Использование переменной связанного типа означает, что задача
TypeVar
будет решена с использованием наиболее специфичного из возможных типов:x = print_capitalized('a string') reveal_type(x) # revealed type is str class StringSubclass(str): pass y = print_capitalized(StringSubclass('another string')) reveal_type(y) # revealed type is StringSubclass z = print_capitalized(45) # error: int is not a subtype of str
Переменные типа могут быть привязаны к конкретным типам, абстрактным типам (азбуке или протоколам) и даже объединениям типов:
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
Однако использование переменной типа constrained означает, что
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__¶
Был ли тип var помечен как ковариантный.
- __contravariant__¶
Был ли тип var помечен как контравариантный.
- __bound__¶
Привязка переменной типа, если таковая имеется.
- __constraints__¶
Кортеж, содержащий ограничения переменной типа, если таковые имеются.
- class typing.TypeVarTuple(name)¶
Введите переменную tuple. Специализированная форма type variable, которая позволяет использовать вариативные обобщения.
Использование:
T = TypeVar("T") Ts = TypeVarTuple("Ts") def move_first_element_to_last(tup: tuple[T, *Ts]) -> tuple[*Ts, T]: return (*tup[1:], tup[0])
Переменная обычного типа позволяет выполнять параметризацию с помощью одного типа. Переменная типа tuple, напротив, позволяет выполнять параметризацию с помощью произвольного количества типов, действуя как произвольное количество переменных типа, заключенных в кортеж. Например:
# T is bound to int, Ts is bound to () # Return value is (1,), which has type tuple[int] move_first_element_to_last(tup=(1,)) # T is bound to int, Ts is bound to (str,) # Return value is ('spam', 1), which has type tuple[str, int] move_first_element_to_last(tup=(1, 'spam')) # T is bound to int, Ts is bound to (str, float) # Return value is ('spam', 3.0, 1), which has type tuple[str, float, int] move_first_element_to_last(tup=(1, 'spam', 3.0)) # This fails to type check (and fails at runtime) # because tuple[()] is not compatible with tuple[T, *Ts] # (at least one element is required) move_first_element_to_last(tup=())
Обратите внимание на использование оператора распаковки
*
вtuple[T, *Ts]
. Концептуально вы можете представитьTs
как набор переменных типа(T1, T2, ...)
.tuple[T, *Ts]
тогда это будетtuple[T, *(T1, T2, ...)]
, что эквивалентноtuple[T, T1, T2, ...]
. (Обратите внимание, что в более старых версиях Python вы могли увидеть, что это написано с использованиемUnpack
вместоUnpack[Ts]
.)Кортежи переменных типа должны всегда быть распакованы. Это помогает отличать кортежи переменных типа от обычных переменных типа:
x: Ts # Not valid x: tuple[Ts] # Not valid x: tuple[*Ts] # The correct way to do it
Кортежи переменных типа могут использоваться в тех же контекстах, что и переменные обычного типа. Например, в определениях классов, аргументах и возвращаемых типах:
Shape = TypeVarTuple("Shape") class Array(Generic[*Shape]): def __getitem__(self, key: tuple[*Shape]) -> float: ... def __abs__(self) -> "Array[*Shape]": ... def get_shape(self) -> tuple[*Shape]: ...
Кортежи переменных типа можно успешно комбинировать с переменными обычного типа:
DType = TypeVar('DType') Shape = TypeVarTuple('Shape') class Array(Generic[DType, *Shape]): # This is fine pass class Array2(Generic[*Shape, DType]): # This would also be fine pass class Height: ... class Width: ... float_array_1d: Array[float, Height] = Array() # Totally fine int_array_2d: Array[int, Height, Width] = Array() # Yup, fine too
Однако обратите внимание, что в одном списке аргументов типа или параметров типа может отображаться не более одного кортежа переменных типа:
x: tuple[*Ts, *Ts] # Not valid class Array(Generic[*Shape, *Shape]): # Not valid pass
Наконец, распакованный кортеж переменной типа type можно использовать в качестве аннотации типа
*args
:def call_soon( callback: Callable[[*Ts], None], *args: *Ts ) -> None: ... callback(*args)
В отличие от нераспакованных аннотаций
*args
- например,*args: int
, в которых указывалось бы, что все аргументы являютсяint
-*args: *Ts
позволяет ссылаться на типы отдельных аргументов в*args
. В данном случае это позволяет нам гарантировать, что типы*args
, передаваемые вcall_soon
, соответствуют типам (позиционных) аргументовcallback
.Смотрите PEP 646 для получения более подробной информации о кортежах переменных типа.
- __name__¶
Имя переменной типа tuple (кортеж).
Добавлено в версии 3.11.
- class typing.ParamSpec(name, *, bound=None, covariant=False, contravariant=False)¶
Переменная спецификации параметра. Специализированная версия type variables.
Использование:
P = ParamSpec('P')
Переменные спецификации параметров существуют в основном для проверки статических типов. Они используются для пересылки типов параметров одного вызываемого объекта другому вызываемому объекту - шаблон, обычно встречающийся в функциях и декораторах более высокого порядка. Они допустимы только при использовании в
Concatenate
, или в качестве первого аргументаCallable
, или в качестве параметров для пользовательских обобщенных типов. Дополнительную информацию о обобщенных типах смотрите вGeneric
.Например, чтобы добавить в функцию базовое ведение журнала, можно создать декоратор
add_logging
для ведения журнала вызовов функций. Переменная спецификации параметра сообщает программе проверки типов, что вызываемый объект, переданный в декоратор, и новый вызываемый объект, возвращаемый им, имеют взаимозависимые параметры типа:from collections.abc import Callable from typing import TypeVar, ParamSpec import logging T = TypeVar('T') P = ParamSpec('P') def add_logging(f: Callable[P, T]) -> Callable[P, T]: '''A type-safe decorator to add logging to a function.''' def inner(*args: P.args, **kwargs: P.kwargs) -> T: logging.info(f'{f.__name__} was called') return f(*args, **kwargs) return inner @add_logging def add_two(x: float, y: float) -> float: '''Add two numbers together.''' return x + y
Без
ParamSpec
Самым простым способом аннотирования этого ранее было использованиеTypeVar
с привязкойCallable[..., Any]
. Однако это вызывает две проблемы:Средство проверки типов не может проверить ввод с помощью функции
inner
, потому что*args
и**kwargs
должны быть введеныAny
.cast()
может потребоваться в телеadd_logging
декоратора при возврате функцииinner
, или необходимо указать средству проверки статического типа игнорироватьreturn inner
.
- args¶
- kwargs¶
Поскольку
ParamSpec
содержит как позиционные, так и ключевые параметры,P.args
иP.kwargs
можно использовать для разделенияParamSpec
на составляющие.P.args
представляет набор позиционных параметров в данном вызове и должен использоваться только для аннотирования*args
.P.kwargs
представляет собой сопоставление параметров ключевых слов с их значениями в данном вызове и должен использоваться только для аннотирования**kwargs
. Оба атрибута требуют, чтобы аннотированный параметр находился в области видимости. Во время выполненияP.args
иP.kwargs
являются экземплярами соответственноParamSpecArgs
иParamSpecKwargs
.
- __name__¶
Название спецификации параметра.
Переменные спецификации параметров, созданные с помощью
covariant=True
илиcontravariant=True
, могут использоваться для объявления ковариантных или контравариантных универсальных типов. Также принимается аргументbound
, аналогичный аргументуTypeVar
. Однако фактическая семантика этих ключевых слов еще не определена.Добавлено в версии 3.10.
Примечание
Можно выбрать только переменные спецификации параметров, определенные в глобальной области видимости.
См.также
PEP 612 – Переменные спецификации параметров (PEP, который ввел
ParamSpec
иConcatenate
)
- typing.ParamSpecArgs¶
- typing.ParamSpecKwargs¶
Аргументы и атрибуты аргументов ключевого слова a
ParamSpec
. АтрибутP.args
дляParamSpec
является экземпляромParamSpecArgs
, аP.kwargs
является экземпляромParamSpecKwargs
. Они предназначены для самоанализа во время выполнения и не имеют особого значения для проверки статических типов.Вызов
get_origin()
для любого из этих объектов вернет исходное значениеParamSpec
:>>> from typing import ParamSpec, get_origin >>> P = ParamSpec("P") >>> get_origin(P.args) is P True >>> get_origin(P.kwargs) is P True
Добавлено в версии 3.10.
Другие специальные директивы¶
Эти функции и классы не должны использоваться непосредственно в качестве аннотаций. Их предполагаемое назначение - быть строительными блоками для создания и объявления типов.
- class typing.NamedTuple¶
Напечатанная версия
collections.namedtuple()
.Использование:
class Employee(NamedTuple): name: str id: int
Это эквивалентно:
Employee = collections.namedtuple('Employee', ['name', 'id'])
Чтобы присвоить полю значение по умолчанию, вы можете присвоить его в теле класса:
class Employee(NamedTuple): name: str id: int = 3 employee = Employee('Guido') assert employee.id == 3
Поля со значением по умолчанию должны располагаться после всех полей без значения по умолчанию.
Результирующий класс имеет дополнительный атрибут
__annotations__
, задающий dict, который сопоставляет имена полей с типами полей. (Имена полей указаны в атрибуте_fields
, а значения по умолчанию - в атрибуте_field_defaults
, оба из которых являются частью APInamedtuple()
.)NamedTuple
подклассы также могут иметь строки документации и методы:class Employee(NamedTuple): """Represents an employee.""" name: str id: int = 3 def __repr__(self) -> str: return f'<Employee {self.name}, id={self.id}>'
NamedTuple
подклассы могут быть универсальными:class Group(NamedTuple, Generic[T]): key: T group: list[T]
Использование с обратной совместимостью:
Employee = NamedTuple('Employee', [('name', str), ('id', int)])
Изменено в версии 3.6: Добавлена поддержка синтаксиса аннотаций переменных PEP 526.
Изменено в версии 3.6.1: Добавлена поддержка значений по умолчанию, методов и строк документации.
Изменено в версии 3.8: Атрибуты
_field_types
и__annotations__
теперь являются обычными словарями, а не экземплярамиOrderedDict
.Изменено в версии 3.9: Удален атрибут
_field_types
в пользу более стандартного атрибута__annotations__
, который содержит ту же информацию.Изменено в версии 3.11: Добавлена поддержка универсальных именованных наборов.
- class typing.NewType(name, tp)¶
Вспомогательный класс для создания малозатратных distinct types.
Средство проверки типов рассматривает
NewType
как отдельный тип. Однако во время выполнения вызовNewType
возвращает его аргумент без изменений.Использование:
UserId = NewType('UserId', int) # Declare the NewType "UserId" first_user = UserId(1) # "UserId" returns the argument unchanged at runtime
- __module__¶
Модуль, в котором определен новый тип.
- __name__¶
Название нового типа.
- __supertype__¶
Тип, на котором основан новый тип.
Добавлено в версии 3.5.2.
Изменено в версии 3.10:
NewType
теперь это скорее класс, чем функция.
- class typing.Protocol(Generic)¶
Базовый класс для классов протоколов.
Классы протоколов определяются следующим образом:
class Proto(Protocol): def meth(self) -> int: ...
Такие классы в основном используются со статическими средствами проверки типов, которые распознают структурные подтипы (статическая утиная типизация), например:
class C: def meth(self) -> int: return 0 def func(x: Proto) -> int: return x.meth() func(C()) # Passes static type check
Смотрите PEP 544 для получения более подробной информации. Классы протоколов, оформленные как
runtime_checkable()
(описанные ниже), действуют как простые протоколы времени выполнения, которые проверяют только наличие заданных атрибутов, игнорируя их сигнатуры типов.Классы протоколов могут быть универсальными, например:
T = TypeVar("T") class GenProto(Protocol[T]): def meth(self) -> T: ...
Добавлено в версии 3.8.
- @typing.runtime_checkable¶
Отметьте класс протокола как протокол времени выполнения.
Такой протокол может использоваться с
isinstance()
иissubclass()
. При применении к классу, не поддерживающему протокол, возникаетTypeError
. Это позволяет провести простую структурную проверку, очень похожую на «пони с одним трюком» вcollections.abc
, например, вIterable
. Например:@runtime_checkable class Closable(Protocol): def close(self): ... assert isinstance(open('/some/file'), Closable) @runtime_checkable class Named(Protocol): name: str import threading assert isinstance(threading.Thread(name='Bob'), Named)
Примечание
runtime_checkable()
будет проверяться только наличие требуемых методов или атрибутов, а не их сигнатур или типов. Например,ssl.SSLObject
является классом, поэтому он проходит проверкуissubclass()
на соответствие Callable. Однако методssl.SSLObject.__init__
существует только для того, чтобы вызватьTypeError
с более информативным сообщением, что делает невозможным вызов (создание экземпляра)ssl.SSLObject
.Примечание
Проверка
isinstance()
по протоколу, проверяемому во время выполнения, может быть на удивление медленной по сравнению с проверкойisinstance()
по классу, не являющемуся протоколом. Рассмотрите возможность использования альтернативных идиом, таких какhasattr()
, для структурных проверок в коде, чувствительном к производительности.Добавлено в версии 3.8.
- class typing.TypedDict(dict)¶
Специальная конструкция для добавления подсказок по типу в словарь. Во время выполнения это обычный
dict
.TypedDict
объявляет тип словаря, который ожидает, что все его экземпляры будут иметь определенный набор ключей, где каждый ключ связан со значением согласованного типа. Это ожидание не проверяется во время выполнения, а выполняется только средствами проверки типов. Использование:class Point2D(TypedDict): x: int y: int label: str a: Point2D = {'x': 1, 'y': 2, 'label': 'good'} # OK b: Point2D = {'z': 3, 'label': 'bad'} # Fails type check assert Point2D(x=1, y=2, label='first') == dict(x=1, y=2, label='first')
Чтобы разрешить использование этой функции в более старых версиях Python, которые не поддерживают PEP 526,
TypedDict
поддерживает две дополнительные эквивалентные синтаксические формы:Используя литерал
dict
в качестве второго аргумента:Point2D = TypedDict('Point2D', {'x': int, 'y': int, 'label': str})
Использование аргументов ключевых слов:
Point2D = TypedDict('Point2D', x=int, y=int, label=str)
Утратил актуальность с версии 3.11, будет удален в версии 3.13: Синтаксис ключевого слова-аргумента устарел в версии 3.11 и будет удален в версии 3.13. Он также может не поддерживаться средствами статической проверки типов.
Функциональный синтаксис также следует использовать, когда какой-либо из ключей недопустим identifiers, например, потому, что они являются ключевыми словами или содержат дефисы. Пример:
# raises SyntaxError class Point2D(TypedDict): in: int # 'in' is a keyword x-y: int # name with hyphens # OK, functional syntax Point2D = TypedDict('Point2D', {'in': int, 'x-y': int})
По умолчанию все ключи должны присутствовать в виде
TypedDict
. Можно пометить отдельные ключи как необязательные, используяNotRequired
:class Point2D(TypedDict): x: int y: int label: NotRequired[str] # Alternative syntax Point2D = TypedDict('Point2D', {'x': int, 'y': int, 'label': NotRequired[str]})
Это означает, что в
Point2D
TypedDict
может быть пропущен ключlabel
.Также можно пометить все ключи как необязательные по умолчанию, указав общее значение
False
:class Point2D(TypedDict, total=False): x: int y: int # Alternative syntax Point2D = TypedDict('Point2D', {'x': int, 'y': int}, total=False)
Это означает, что в a
Point2D
TypedDict
может быть пропущен любой из ключей. Ожидается, что средство проверки типов будет поддерживать только литералFalse
илиTrue
в качестве значения аргументаtotal
.True
используется по умолчанию и делает обязательными все элементы, определенные в теле класса.Отдельные клавиши a
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
может быть общим:T = TypeVar("T") class Group(TypedDict, Generic[T]): key: T group: list[T]
Значение
TypedDict
может быть проанализировано с помощью аннотаций (см. Аннотации к лучшим практикам для получения дополнительной информации о рекомендациях по аннотациям),__total__
,__required_keys__
, и__optional_keys__
.- __total__¶
Point2D.__total__
возвращает значение аргументаtotal
. Пример:>>> from typing import TypedDict >>> class Point2D(TypedDict): pass >>> Point2D.__total__ True >>> class Point2D(TypedDict, total=False): pass >>> Point2D.__total__ False >>> class Point3D(Point2D): pass >>> Point3D.__total__ True
Этот атрибут отражает только значение аргумента
total
для текущего классаTypedDict
, а не то, является ли класс семантически полным. Например,TypedDict
с__total__
, равным True, может содержать ключи, помеченные какNotRequired
, или может наследоваться от другогоTypedDict
сtotal=False
. Поэтому, как правило, лучше использовать__required_keys__
и__optional_keys__
для самоанализа.
- __required_keys__¶
Добавлено в версии 3.9.
- __optional_keys__¶
Point2D.__required_keys__
иPoint2D.__optional_keys__
возвращаютfrozenset
объекты, содержащие обязательные и необязательные ключи соответственно.Клавиши, помеченные
Required
, всегда будут отображаться в__required_keys__
, а клавиши, помеченныеNotRequired
, всегда будут отображаться в__optional_keys__
.Для обеспечения обратной совместимости с Python 3.10 и ниже также возможно использовать наследование для объявления как обязательных, так и необязательных ключей в одном и том же
TypedDict
. Это делается путем объявленияTypedDict
с одним значением для аргументаtotal
и последующего наследования от него в другомTypedDict
с другим значением дляtotal
:>>> class Point2D(TypedDict, total=False): ... x: int ... y: int ... >>> class Point3D(Point2D): ... z: int ... >>> Point3D.__required_keys__ == frozenset({'z'}) True >>> Point3D.__optional_keys__ == frozenset({'x', 'y'}) True
Добавлено в версии 3.9.
Примечание
Если используется
from __future__ import annotations
или если аннотации заданы в виде строк, аннотации не вычисляются, когда определено значениеTypedDict
. Следовательно, самоанализ во время выполнения, на который опираются__required_keys__
и__optional_keys__
, может работать неправильно, а значения атрибутов могут быть неверными.
Смотрите PEP 589 для получения дополнительных примеров и подробных правил использования
TypedDict
.Добавлено в версии 3.8.
Изменено в версии 3.11: Добавлена поддержка пометки отдельных клавиш как
Required
илиNotRequired
. Смотрите PEP 655.Изменено в версии 3.11: Добавлена поддержка общих
TypedDict
s.
Протоколы¶
Следующие протоколы предоставляются модулем ввода текста. Все они помечены символом @runtime_checkable
.
- class typing.SupportsAbs¶
ABC с одним абстрактным методом
__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¶
ABC с одним абстрактным методом
__round__
, который является ковариантным по типу возвращаемого значения.
Азбука работы с вводом-выводом¶
Функции и декораторы¶
- typing.cast(typ, val)¶
Приведите значение к определенному типу.
Это возвращает значение без изменений. Для средства проверки типов это сигнализирует о том, что возвращаемое значение имеет указанный тип, но во время выполнения мы намеренно ничего не проверяем (мы хотим, чтобы это было как можно быстрее).
- typing.assert_type(val, typ, /)¶
Попросите средство проверки статического типа подтвердить, что val имеет предполагаемый тип typ.
Во время выполнения это ничего не делает: он возвращает первый аргумент без изменений, без проверок или побочных эффектов, независимо от фактического типа аргумента.
Когда средство проверки статического типа обнаруживает вызов
assert_type()
, оно выдает ошибку, если значение не относится к указанному типу:def greet(name: str) -> None: assert_type(name, str) # OK, inferred type of `name` is `str` assert_type(name, int) # type checker error
Эта функция полезна для обеспечения того, чтобы программа проверки типов понимала сценарий в соответствии с намерениями разработчика:
def complex_function(arg: object): # Do some complex type-narrowing logic, # after which we hope the inferred type will be `int` ... # Test whether the type checker correctly understands our function assert_type(arg, int)
Добавлено в версии 3.11.
- typing.assert_never(arg, /)¶
Попросите средство проверки статического типа подтвердить, что строка кода недоступна.
Пример:
def int_or_str(arg: int | str) -> None: match arg: case int(): print("It's an int") case str(): print("It's a str") case _ as unreachable: assert_never(unreachable)
Здесь аннотации позволяют программе проверки типов сделать вывод, что последний вариант никогда не может быть выполнен, потому что
arg
является либоint
, либоstr
, и оба варианта рассматриваются в более ранних вариантах.Если средство проверки типов обнаружит, что вызов
assert_never()
доступен, оно выдаст ошибку. Например, если бы аннотация типа дляarg
была вместоint | str | float
, средство проверки типов выдало бы ошибку, указывающую на то, чтоunreachable
относится к типуfloat
. Чтобы вызовassert_never
прошел проверку типа, предполагаемый тип передаваемого аргумента должен быть нижним типом,Never
, и никаким другим.Во время выполнения при вызове этого параметра возникает исключение.
См.также
Unreachable Code and Exhaustiveness Checking содержит больше информации о проверке полноты с помощью статической типизации.
Добавлено в версии 3.11.
- typing.reveal_type(obj, /)¶
Попросите средство проверки статического типа указать предполагаемый тип выражения.
Когда средство статической проверки типов обнаруживает вызов этой функции, оно выдает диагностический запрос с предполагаемым типом аргумента. Например:
x: int = 1 reveal_type(x) # Revealed type is "builtins.int"
Это может быть полезно, когда вы хотите отладить, как ваша программа проверки типов обрабатывает определенный фрагмент кода.
Во время выполнения эта функция выводит тип своего аргумента во время выполнения равным
sys.stderr
и возвращает аргумент без изменений (позволяя использовать вызов в выражении).:x = reveal_type(1) # prints "Runtime type is int" print(x) # prints "1"
Обратите внимание, что тип среды выполнения может отличаться (более или менее специфично) от типа, статически выводимого средством проверки типов.
Большинство средств проверки типов поддерживают
reveal_type()
везде, даже если имя не импортировано изtyping
. Однако импорт имени изtyping
позволяет вашему коду выполняться без ошибок во время выполнения и более четко передает намерение.Добавлено в версии 3.11.
- @typing.dataclass_transform(*, eq_default=True, order_default=False, kw_only_default=False, field_specifiers=(), **kwargs)¶
Декоратор, чтобы пометить объект как обеспечивающий поведение, подобное
dataclass
.dataclass_transform
может использоваться для оформления класса, метакласса или функции, которая сама по себе является декоратором. Наличие@dataclass_transform()
сообщает средству проверки статического типа, что оформленный объект выполняет «волшебство» во время выполнения, которое преобразует класс аналогично@dataclasses.dataclass
.Пример использования с функцией декоратора:
T = TypeVar("T") @dataclass_transform() def create_model(cls: type[T]) -> type[T]: ... return cls @create_model class CustomerModel: id: int name: str
В базовом классе:
@dataclass_transform() class ModelBase: ... class CustomerModel(ModelBase): id: int name: str
В метаклассе:
@dataclass_transform() class ModelMeta(type): ... class ModelBase(metaclass=ModelMeta): ... class CustomerModel(ModelBase): id: int name: str
Классы
CustomerModel
, определенные выше, будут обрабатываться средствами проверки типов аналогично классам, созданным с помощью@dataclasses.dataclass
. Например, средства проверки типов будут предполагать, что у этих классов есть__init__
методы, которые принимаютid
иname
.Оформленный класс, метакласс или функция могут принимать следующие аргументы bool, которые, как предполагают средства проверки типов, будут иметь тот же эффект, что и в случае с
@dataclasses.dataclass
декоратором:init
,eq
,order
,unsafe_hash
,frozen
,match_args
,kw_only
, иslots
. Должна быть предусмотрена возможность статической оценки значений этих аргументов (True
илиFalse
).Аргументы
dataclass_transform
декоратора можно использовать для настройки поведения оформленного класса, метакласса или функции по умолчанию:- Parameters:
eq_default (bool) – Указывает, принимается ли значение параметра
eq
равнымTrue
илиFalse
, если он опущен вызывающей стороной. По умолчанию используется значениеTrue
.order_default (bool) – Указывает, принимается ли значение параметра
order
равнымTrue
илиFalse
, если он опущен вызывающей стороной. По умолчанию используется значениеFalse
.kw_only_default (bool) – Указывает, принимается ли значение параметра
kw_only
равнымTrue
илиFalse
, если он опущен вызывающей стороной. По умолчанию используется значениеFalse
.field_specifiers (tuple[Callable[..., Any], ...]) – Определяет статический список поддерживаемых классов или функций, описывающих поля, аналогично
dataclasses.field()
. По умолчанию используется()
.**kwargs (Any) – Принимаются произвольные другие аргументы ключевого слова, чтобы обеспечить возможность будущих расширений.
Средства проверки типов распознают следующие необязательные параметры в спецификаторах полей:
Распознанные параметры для спецификаторов полей¶ Имя параметра
Описание
init
Указывает, должно ли поле быть включено в синтезированный метод
__init__
. Если не указано,init
по умолчанию используетсяTrue
.default
Задает значение по умолчанию для этого поля.
default_factory
Обеспечивает обратный вызов во время выполнения, который возвращает значение по умолчанию для поля. Если не указаны ни
default
, ниdefault_factory
, предполагается, что поле не имеет значения по умолчанию, и ему должно быть предоставлено значение при создании экземпляра класса.factory
Псевдоним для параметра
default_factory
в спецификаторах полей.kw_only
Указывает, должно ли поле быть помечено как доступное только для ключевых слов. Если
True
, поле будет доступно только для ключевых слов. ЕслиFalse
, оно не будет доступно только для ключевых слов. Если не указано, то будет использовано значение параметраkw_only
для объекта, оформленного какdataclass_transform
, или, если оно не указано, будет использовано значениеkw_only_default
дляdataclass_transform
.alias
Предоставляет альтернативное имя для поля. Это альтернативное имя используется в синтезированном методе
__init__
.Во время выполнения этот декоратор записывает свои аргументы в атрибут
__dataclass_transform__
оформляемого объекта. Это не имеет никакого другого эффекта во время выполнения.Смотрите PEP 681 для получения более подробной информации.
Добавлено в версии 3.11.
- @typing.overload¶
Декоратор для создания перегруженных функций и методов.
Декоратор
@overload
позволяет описывать функции и методы, которые поддерживают множество различных комбинаций типов аргументов. За серией определений, оформленных@overload
, должно следовать ровно одно определение, не оформленное@overload
(для той же функции/метода).@overload
-оформленные определения предназначены только для проверки типов, поскольку они будут перезаписаны определением, не содержащим@overload
-оформленного текста. Между тем, определение, не содержащее@overload
, будет использоваться во время выполнения, но должно игнорироваться средством проверки типов. Во время выполнения прямой вызов функции, содержащей@overload
, вызоветNotImplementedError
.Пример перегрузки, которая дает более точный тип, чем может быть выражен с помощью объединения или переменной типа:
@overload def process(response: None) -> None: ... @overload def process(response: int) -> tuple[int, str]: ... @overload def process(response: bytes) -> str: ... def process(response): ... # actual implementation goes here
Смотрите PEP 484 для получения более подробной информации и сравнения с другой семантикой ввода.
Изменено в версии 3.11: Перегруженные функции теперь можно анализировать во время выполнения с помощью
get_overloads()
.
- typing.get_overloads(func)¶
Возвращает последовательность
@overload
-оформленных определений для func.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¶
Декоратор, указывающий на то, что аннотации не являются подсказками к типу текста.
Это работает как класс или функция decorator. В случае класса это рекурсивно применяется ко всем методам и классам, определенным в этом классе (но не к методам, определенным в его суперклассах или подклассах). Средства проверки типов будут игнорировать все аннотации в функции или классе с этим декоратором.
@no_type_check
изменяет оформленный объект на месте.
- @typing.no_type_check_decorator¶
Декоратор, чтобы придать другому декоратору эффект
no_type_check()
.Это оборачивает декоратор чем-то, что оборачивает оформленную функцию в
no_type_check()
.
- @typing.type_check_only¶
Декоратор, позволяющий пометить класс или функцию как недоступные во время выполнения.
Сам по себе этот декоратор недоступен во время выполнения. В основном он предназначен для обозначения классов, определенных в файлах-заглушках типов, если реализация возвращает экземпляр закрытого класса:
@type_check_only class Response: # private or not available at runtime code: int def get_header(self, name: str) -> str: ... def fetch_response() -> Response: ...
Обратите внимание, что возвращать экземпляры закрытых классов не рекомендуется. Обычно предпочтительнее делать такие классы общедоступными.
Помощники в самоанализе¶
- typing.get_type_hints(obj, globalns=None, localns=None, include_extras=False)¶
Возвращает словарь, содержащий подсказки по типу функции, метода, модуля или объекта класса.
Это часто совпадает с
obj.__annotations__
. Кроме того, прямые ссылки, закодированные в виде строковых литералов, обрабатываются путем их вычисления в пространствах именglobals
иlocals
. Для классаC
верните словарь, созданный путем объединения всех__annotations__
иC.__mro__
в обратном порядке.Функция рекурсивно заменяет все
Annotated[T, ...]
наT
, если только дляinclude_extras
не задано значениеTrue
(дополнительную информацию смотрите в разделеAnnotated
). Например:class Student(NamedTuple): name: Annotated[str, 'some marker'] assert get_type_hints(Student) == {'name': str} assert get_type_hints(Student, include_extras=False) == {'name': str} assert get_type_hints(Student, include_extras=True) == { 'name': Annotated[str, 'some marker'] }
Примечание
get_type_hints()
не работает с импортированными type aliases, которые содержат прямые ссылки. Включение отложенной оценки аннотаций (PEP 563) может устранить необходимость в большинстве прямых ссылок.Изменено в версии 3.9: Добавлен параметр
include_extras
как часть параметра PEP 593. Дополнительную информацию смотрите в документации поAnnotated
.Изменено в версии 3.11: Ранее для аннотаций функций и методов добавлялось значение
Optional[t]
, если было установлено значение по умолчанию, равноеNone
. Теперь аннотация возвращается без изменений.
- typing.get_origin(tp)¶
Получите неподписанную версию типа: для объекта ввода вида
X[Y, Z, ...]
вернитеX
.Если
X
является псевдонимом модуля ввода для здания или классаcollections
, он будет нормализован к исходному классу. ЕслиX
является экземпляромParamSpecArgs
илиParamSpecKwargs
, верните базовыйParamSpec
. Для неподдерживаемых объектов вернитеNone
.Примеры:
assert get_origin(str) is None assert get_origin(Dict[str, int]) is dict assert get_origin(Union[int, str]) is Union P = ParamSpec('P') assert get_origin(P.args) is P assert get_origin(P.kwargs) is P
Добавлено в версии 3.8.
- typing.get_args(tp)¶
Получите типовые документы со всеми выполненными заменами: для вводимого объекта вида
X[Y, Z, ...]
верните(Y, Z, ...)
.Если
X
является объединением илиLiteral
содержится в другом универсальном типе, порядок(Y, Z, ...)
может отличаться от порядка исходных аргументов[Y, Z, ...]
из-за кэширования типов. Возвращает()
для неподдерживаемых объектов.Примеры:
assert get_args(int) == () assert get_args(Dict[int, str]) == (int, str) assert get_args(Union[int, str]) == (int, str)
Добавлено в версии 3.8.
- typing.is_typeddict(tp)¶
Проверьте, является ли тип
TypedDict
.Например:
class Film(TypedDict): title: str year: int assert is_typeddict(Film) assert not is_typeddict(list | str) # TypedDict is a factory for creating typed dicts, # not a typed dict itself assert not is_typeddict(TypedDict)
Добавлено в версии 3.10.
- class typing.ForwardRef¶
Класс, используемый для внутреннего типизированного представления прямых ссылок на строки.
Например,
List["SomeClass"]
неявно преобразуется вList[ForwardRef("SomeClass")]
.ForwardRef
не должен создаваться пользователем, но может использоваться инструментами самоанализа.Примечание
PEP 585 универсальные типы, такие как
list["SomeClass"]
, не будут неявно преобразованы вlist[ForwardRef("SomeClass")]
и, следовательно, не будут автоматически преобразованы вlist[SomeClass]
.Добавлено в версии 3.7.4.
Постоянный¶
- typing.TYPE_CHECKING¶
Специальная константа, которая, как предполагается, равна
True
сторонними проверяющими статический тип. Во время выполнения она равнаFalse
.Использование:
if TYPE_CHECKING: import expensive_mod def fun(arg: 'expensive_mod.SomeType') -> None: local_var: expensive_mod.AnotherType = other_fun()
Аннотация первого типа должна быть заключена в кавычки, что делает ее «прямой ссылкой», чтобы скрыть ссылку
expensive_mod
от среды выполнения интерпретатора. Аннотации типов для локальных переменных не вычисляются, поэтому вторую аннотацию не нужно заключать в кавычки.Примечание
Если используется
from __future__ import annotations
, аннотации не вычисляются во время определения функции. Вместо этого они сохраняются в виде строк в__annotations__
. Это избавляет от необходимости заключать аннотацию в кавычки (см. PEP 563).Добавлено в версии 3.5.2.
Устаревшие псевдонимы¶
Этот модуль определяет несколько устаревших псевдонимов для уже существующих стандартных библиотечных классов. Изначально они были включены в модуль ввода текста, чтобы поддерживать параметризацию этих универсальных классов с помощью []
. Однако псевдонимы стали излишними в Python 3.9, когда соответствующие ранее существовавшие классы были расширены для поддержки []
(см. PEP 585).
Избыточные типы устарели начиная с версии Python 3.9. Однако, хотя псевдонимы могут быть удалены в какой-то момент, в настоящее время удаление этих псевдонимов не планируется. Таким образом, интерпретатор в настоящее время не выдает предупреждений об устаревании для этих псевдонимов.
Если в какой-то момент будет решено удалить эти устаревшие псевдонимы, интерпретатор выдаст предупреждение об устаревании как минимум за два выпуска до удаления. Псевдонимы гарантированно останутся в модуле ввода текста без предупреждений об устаревании как минимум до Python 3.14.
Специалистам по проверке типов рекомендуется отмечать использование устаревших типов, если программа, которую они проверяют, нацелена как минимум на версию Python 3.9 или новее.
Псевдонимы для встроенных типов¶
- class typing.Dict(dict, MutableMapping[KT, VT])¶
Устаревший псевдоним
dict
.Обратите внимание, что для аннотирования аргументов предпочтительнее использовать абстрактный тип коллекции, такой как
Mapping
, а неdict
илиtyping.Dict
.Этот тип может быть использован следующим образом:
def count_words(text: str) -> Dict[str, int]: ...
Не рекомендуется, начиная с версии 3.9:
builtins.dict
теперь поддерживается подписка ([]
). Смотрите PEP 585 и Общий тип псевдонима.
- class typing.List(list, MutableSequence[T])¶
Устаревший псевдоним
list
.Обратите внимание, что для аннотирования аргументов предпочтительнее использовать абстрактный тип коллекции, такой как
Sequence
илиIterable
, а неlist
илиtyping.List
.Этот тип может быть использован следующим образом:
T = TypeVar('T', int, float) def vec2(x: T, y: T) -> List[T]: return [x, y] def keep_positives(vector: Sequence[T]) -> List[T]: return [item for item in vector if item > 0]
Не рекомендуется, начиная с версии 3.9:
builtins.list
теперь поддерживается подписка ([]
). Смотрите PEP 585 и Общий тип псевдонима.
- class typing.Set(set, MutableSet[T])¶
Устаревший псевдоним
builtins.set
.Обратите внимание, что для аннотирования аргументов предпочтительнее использовать абстрактный тип коллекции, такой как
AbstractSet
, а неset
илиtyping.Set
.Не рекомендуется, начиная с версии 3.9:
builtins.set
теперь поддерживается подписка ([]
). Смотрите PEP 585 и Общий тип псевдонима.
- class typing.FrozenSet(frozenset, AbstractSet[T_co])¶
Устаревший псевдоним
builtins.frozenset
.Не рекомендуется, начиная с версии 3.9:
builtins.frozenset
теперь поддерживается подписка ([]
). Смотрите PEP 585 и Общий тип псевдонима.
- typing.Tuple¶
Устаревший псевдоним для
tuple
.tuple
иTuple
имеют особый регистр в системе типов; более подробную информацию смотрите в Кортежи аннотаций.Не рекомендуется, начиная с версии 3.9:
builtins.tuple
теперь поддерживается подписка ([]
). Смотрите PEP 585 и Общий тип псевдонима.
- class typing.Type(Generic[CT_co])¶
Устаревший псевдоним
type
.Смотрите Тип объектов класса для получения подробной информации об использовании
type
илиtyping.Type
в аннотациях к типу.Добавлено в версии 3.5.2.
Не рекомендуется, начиная с версии 3.9:
builtins.type
теперь поддерживается подписка ([]
). Смотрите PEP 585 и Общий тип псевдонима.
Псевдонимы для типов в collections
¶
- class typing.DefaultDict(collections.defaultdict, MutableMapping[KT, VT])¶
Устаревший псевдоним
collections.defaultdict
.Добавлено в версии 3.5.2.
Не рекомендуется, начиная с версии 3.9:
collections.defaultdict
теперь поддерживается подписка ([]
). Смотрите PEP 585 и Общий тип псевдонима.
- class typing.OrderedDict(collections.OrderedDict, MutableMapping[KT, VT])¶
Устаревший псевдоним
collections.OrderedDict
.Добавлено в версии 3.7.2.
Не рекомендуется, начиная с версии 3.9:
collections.OrderedDict
теперь поддерживается подписка ([]
). Смотрите PEP 585 и Общий тип псевдонима.
- class typing.ChainMap(collections.ChainMap, MutableMapping[KT, VT])¶
Устаревший псевдоним
collections.ChainMap
.Добавлено в версии 3.6.1.
Не рекомендуется, начиная с версии 3.9:
collections.ChainMap
теперь поддерживается подписка ([]
). Смотрите PEP 585 и Общий тип псевдонима.
- class typing.Counter(collections.Counter, Dict[T, int])¶
Устаревший псевдоним
collections.Counter
.Добавлено в версии 3.6.1.
Не рекомендуется, начиная с версии 3.9:
collections.Counter
теперь поддерживается подписка ([]
). Смотрите PEP 585 и Общий тип псевдонима.
- class typing.Deque(deque, MutableSequence[T])¶
Устаревший псевдоним
collections.deque
.Добавлено в версии 3.6.1.
Не рекомендуется, начиная с версии 3.9:
collections.deque
теперь поддерживается подписка ([]
). Смотрите PEP 585 и Общий тип псевдонима.
Псевдонимы для других конкретных типов¶
- class typing.Pattern¶
- class typing.Match¶
Устаревшие псевдонимы, соответствующие типам возвращаемых значений из
re.compile()
иre.match()
.Эти типы (и соответствующие функции) являются универсальными по сравнению с
AnyStr
.Pattern
могут быть специализированными какPattern[str]
илиPattern[bytes]
;Match
могут быть специализированными какMatch[str]
илиMatch[bytes]
.Утратил актуальность с версии 3.8, будет удален в версии 3.13: Пространство имен
typing.re
устарело и будет удалено. Вместо этого эти типы следует напрямую импортировать изtyping
.Не рекомендуется, начиная с версии 3.9: Классы
Pattern
иMatch
изre
теперь поддерживают[]
. Смотрите PEP 585 и Общий тип псевдонима.
- class typing.Text¶
Устаревший псевдоним для
str
.Text
используется для указания прямого пути, совместимого с кодом на Python 2: в Python 2Text
является псевдонимом дляunicode
.Используйте
Text
, чтобы указать, что значение должно содержать строку в юникоде способом, совместимым как с Python2, так и с Python3:def add_unicode_checkmark(text: Text) -> Text: return text + u' \u2713'
Добавлено в версии 3.5.2.
Не рекомендуется, начиная с версии 3.11: Python2 больше не поддерживается, и большинство средств проверки типов также больше не поддерживают проверку типов кода на 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])¶
Этот тип представляет типы
bytes
,bytearray
, иmemoryview
байтовых последовательностей.Утратил актуальность с версии 3.9, будет удален в версии 3.14: Предпочитайте
typing_extensions.Buffer
или объединение типаbytes | bytearray | memoryview
.
- class typing.Collection(Sized, Iterable[T_co], Container[T_co])¶
Устаревший псевдоним
collections.abc.Collection
.Добавлено в версии 3.6.
Не рекомендуется, начиная с версии 3.9:
collections.abc.Collection
теперь поддерживается подписка ([]
). Смотрите PEP 585 и Общий тип псевдонима.
- class typing.Container(Generic[T_co])¶
Устаревший псевдоним
collections.abc.Container
.Не рекомендуется, начиная с версии 3.9:
collections.abc.Container
теперь поддерживается подписка ([]
). Смотрите PEP 585 и Общий тип псевдонима.
- class typing.ItemsView(MappingView, AbstractSet[tuple[KT_co, VT_co]])¶
Устаревший псевдоним
collections.abc.ItemsView
.Не рекомендуется, начиная с версии 3.9:
collections.abc.ItemsView
теперь поддерживается подписка ([]
). Смотрите PEP 585 и Общий тип псевдонима.
- class typing.KeysView(MappingView, AbstractSet[KT_co])¶
Устаревший псевдоним
collections.abc.KeysView
.Не рекомендуется, начиная с версии 3.9:
collections.abc.KeysView
теперь поддерживается подписка ([]
). Смотрите PEP 585 и Общий тип псевдонима.
- class typing.Mapping(Collection[KT], Generic[KT, VT_co])¶
Устаревший псевдоним
collections.abc.Mapping
.Этот тип может быть использован следующим образом:
def get_position_in_index(word_list: Mapping[str, int], word: str) -> int: return word_list[word]
Не рекомендуется, начиная с версии 3.9:
collections.abc.Mapping
теперь поддерживается подписка ([]
). Смотрите PEP 585 и Общий тип псевдонима.
- class typing.MappingView(Sized)¶
Устаревший псевдоним
collections.abc.MappingView
.Не рекомендуется, начиная с версии 3.9:
collections.abc.MappingView
теперь поддерживается подписка ([]
). Смотрите PEP 585 и Общий тип псевдонима.
- class typing.MutableMapping(Mapping[KT, VT])¶
Устаревший псевдоним
collections.abc.MutableMapping
.Не рекомендуется, начиная с версии 3.9:
collections.abc.MutableMapping
теперь поддерживается подписка ([]
). Смотрите PEP 585 и Общий тип псевдонима.
- class typing.MutableSequence(Sequence[T])¶
Устаревший псевдоним
collections.abc.MutableSequence
.Не рекомендуется, начиная с версии 3.9:
collections.abc.MutableSequence
теперь поддерживается подписка ([]
). Смотрите PEP 585 и Общий тип псевдонима.
- class typing.MutableSet(AbstractSet[T])¶
Устаревший псевдоним
collections.abc.MutableSet
.Не рекомендуется, начиная с версии 3.9:
collections.abc.MutableSet
теперь поддерживается подписка ([]
). Смотрите PEP 585 и Общий тип псевдонима.
- class typing.Sequence(Reversible[T_co], Collection[T_co])¶
Устаревший псевдоним
collections.abc.Sequence
.Не рекомендуется, начиная с версии 3.9:
collections.abc.Sequence
теперь поддерживается подписка ([]
). Смотрите PEP 585 и Общий тип псевдонима.
- class typing.ValuesView(MappingView, Collection[_VT_co])¶
Устаревший псевдоним
collections.abc.ValuesView
.Не рекомендуется, начиная с версии 3.9:
collections.abc.ValuesView
теперь поддерживается подписка ([]
). Смотрите PEP 585 и Общий тип псевдонима.
Псевдонимы для асинхронных азбук в collections.abc
¶
- class typing.Coroutine(Awaitable[ReturnType], Generic[YieldType, SendType, ReturnType])¶
Устаревший псевдоним
collections.abc.Coroutine
.Дисперсия и порядок следования переменных типа соответствуют параметрам
Generator
, например:from collections.abc import Coroutine c: Coroutine[list[str], str, int] # Some coroutine defined elsewhere x = c.send('hi') # Inferred type of 'x' is list[str] async def bar() -> None: y = await c # Inferred type of 'y' is int
Добавлено в версии 3.5.3.
Не рекомендуется, начиная с версии 3.9:
collections.abc.Coroutine
теперь поддерживается подписка ([]
). Смотрите PEP 585 и Общий тип псевдонима.
- class typing.AsyncGenerator(AsyncIterator[YieldType], Generic[YieldType, SendType])¶
Устаревший псевдоним
collections.abc.AsyncGenerator
.Асинхронный генератор может быть помечен общим типом
AsyncGenerator[YieldType, SendType]
. Например:async def echo_round() -> AsyncGenerator[int, float]: sent = yield 0 while sent >= 0.0: rounded = await round(sent) sent = yield rounded
В отличие от обычных генераторов, асинхронные генераторы не могут возвращать значение, поэтому параметр типа
ReturnType
отсутствует. Как и в случае сGenerator
,SendType
ведет себя противоречиво.Если ваш генератор выдает только значения, установите для параметра
SendType
значениеNone
:async def infinite_stream(start: int) -> AsyncGenerator[int, None]: while True: yield start start = await increment(start)
В качестве альтернативы, пометьте свой генератор как имеющий возвращаемый тип либо
AsyncIterable[YieldType]
, либоAsyncIterator[YieldType]
:async def infinite_stream(start: int) -> AsyncIterator[int]: while True: yield start start = await increment(start)
Добавлено в версии 3.6.1.
Не рекомендуется, начиная с версии 3.9:
collections.abc.AsyncGenerator
теперь поддерживается подписка ([]
). Смотрите PEP 585 и Общий тип псевдонима.
- class typing.AsyncIterable(Generic[T_co])¶
Устаревший псевдоним
collections.abc.AsyncIterable
.Добавлено в версии 3.5.2.
Не рекомендуется, начиная с версии 3.9:
collections.abc.AsyncIterable
теперь поддерживается подписка ([]
). Смотрите PEP 585 и Общий тип псевдонима.
- class typing.AsyncIterator(AsyncIterable[T_co])¶
Устаревший псевдоним
collections.abc.AsyncIterator
.Добавлено в версии 3.5.2.
Не рекомендуется, начиная с версии 3.9:
collections.abc.AsyncIterator
теперь поддерживается подписка ([]
). Смотрите PEP 585 и Общий тип псевдонима.
- class typing.Awaitable(Generic[T_co])¶
Устаревший псевдоним
collections.abc.Awaitable
.Добавлено в версии 3.5.2.
Не рекомендуется, начиная с версии 3.9:
collections.abc.Awaitable
теперь поддерживается подписка ([]
). Смотрите PEP 585 и Общий тип псевдонима.
Псевдонимы для других азбук в collections.abc
¶
- class typing.Iterable(Generic[T_co])¶
Устаревший псевдоним
collections.abc.Iterable
.Не рекомендуется, начиная с версии 3.9:
collections.abc.Iterable
теперь поддерживается подписка ([]
). Смотрите PEP 585 и Общий тип псевдонима.
- class typing.Iterator(Iterable[T_co])¶
Устаревший псевдоним
collections.abc.Iterator
.Не рекомендуется, начиная с версии 3.9:
collections.abc.Iterator
теперь поддерживается подписка ([]
). Смотрите PEP 585 и Общий тип псевдонима.
- typing.Callable¶
Устаревший псевдоним
collections.abc.Callable
.Смотрите Аннотирование вызываемых объектов для получения подробной информации о том, как использовать
collections.abc.Callable
иtyping.Callable
в аннотациях к типу.Не рекомендуется, начиная с версии 3.9:
collections.abc.Callable
теперь поддерживается подписка ([]
). Смотрите PEP 585 и Общий тип псевдонима.Изменено в версии 3.10:
Callable
теперь поддерживаетParamSpec
иConcatenate
. Более подробную информацию смотрите в PEP 612.
- class typing.Generator(Iterator[YieldType], Generic[YieldType, SendType, ReturnType])¶
Устаревший псевдоним
collections.abc.Generator
.Генератор может быть аннотирован с помощью универсального типа
Generator[YieldType, SendType, ReturnType]
. Например:def echo_round() -> Generator[int, float, str]: sent = yield 0 while sent >= 0: sent = yield round(sent) return 'Done'
Обратите внимание, что в отличие от многих других обобщений в модуле ввода,
SendType
изGenerator
ведет себя как противоречиво, так и ковариантно или инвариантно.Если ваш генератор выдает только значения, установите для
SendType
иReturnType
значениеNone
:def infinite_stream(start: int) -> Generator[int, None, None]: while True: yield start start += 1
В качестве альтернативы, пометьте свой генератор как имеющий возвращаемый тип либо
Iterable[YieldType]
, либоIterator[YieldType]
:def infinite_stream(start: int) -> Iterator[int]: while True: yield start start += 1
Не рекомендуется, начиная с версии 3.9:
collections.abc.Generator
теперь поддерживается подписка ([]
). Смотрите PEP 585 и Общий тип псевдонима.
- class typing.Hashable¶
Псевдоним для
collections.abc.Hashable
.
- class typing.Reversible(Iterable[T_co])¶
Устаревший псевдоним
collections.abc.Reversible
.Не рекомендуется, начиная с версии 3.9:
collections.abc.Reversible
теперь поддерживается подписка ([]
). Смотрите PEP 585 и Общий тип псевдонима.
- class typing.Sized¶
Псевдоним для
collections.abc.Sized
.
Псевдонимы contextlib
Азбука¶
- class typing.ContextManager(Generic[T_co])¶
Устаревший псевдоним
contextlib.AbstractContextManager
.Добавлено в версии 3.5.4.
Не рекомендуется, начиная с версии 3.9:
contextlib.AbstractContextManager
теперь поддерживается подписка ([]
). Смотрите PEP 585 и Общий тип псевдонима.
- class typing.AsyncContextManager(Generic[T_co])¶
Устаревший псевдоним
contextlib.AbstractAsyncContextManager
.Добавлено в версии 3.6.2.
Не рекомендуется, начиная с версии 3.9:
contextlib.AbstractAsyncContextManager
теперь поддерживается подписка ([]
). Смотрите PEP 585 и Общий тип псевдонима.
Временная шкала устаревания основных функций¶
Некоторые функции в typing
являются устаревшими и могут быть удалены в будущих версиях Python. Для вашего удобства в следующей таблице приведены основные устаревшие функции. Это может быть изменено, и в списке указаны не все устаревшие функции.
Особенность |
Устарел в |
Предполагаемое удаление |
ОПТОСОЗ/проблема |
---|---|---|---|
Подмодули |
3.8 |
3.13 |
|
|
3.9 |
Не определились (см. Устаревшие псевдонимы для получения дополнительной информации) |
|
3.9 |
3.14 |
||
3.11 |
Нерешительный |