import typing # Новое в Python 3.10. typing.ParamSpec(name, *, bound=None, covariant=False, contravariant=False) # Использование P = typing.ParamSpec('P')
name
- имя переменной,bound=None
- связанный аргумент, аналогичный TypeVar
,covariant=False
- ковариантный универсальный тип,contravariant=False
- контравариантный универсальный тип.typing.ParamSpec
:Класс ParamSpec()
модуля typing
представляет собой переменные спецификации аргументов. Другими словами это специализированная версия переменной типа typing.TypeVar.
С версии Python 3.12 спецификации параметров теперь можно объявлять с использованием синтаксиса параметра типа, представленного в PEP 695.
В списках параметров типа, спецификации параметров могут быть объявлены с помощью двух звездочек (**
):
type IntFunc[**P] = Callable[P, int]
Для совместимости с Python 3.11 и более ранними версиями объекты ParamSpec
также можно создавать следующим образом:
P = ParamSpec('P')
Переменные спецификации аргументов существуют в первую очередь для целей проверки статических типов. Они используются для пересылки типов параметров одного вызываемого объекта другому вызываемому объекту. Этот шаблон встречается в функциях и декораторах более высокого порядка. Они действительны только при использовании в Concatenate
, или в качестве первого аргумента для Callable
, или в качестве параметров для определяемых пользователем универсальных шаблонов Generic
Теперь, чтобы добавить базовое ведение журнала в функцию, можно создать декоратор @add_logging()
для ведения журнала вызовов функций. Переменная спецификации параметра сообщает средству проверки типов, что вызываемый объект, переданный в декоратор, и новый вызываемый объект, возвращаемый им, имеют взаимозависимые параметры типа:
from collections.abc import Callable import logging def add_logging[T, **P](f: Callable[P, T]) -> Callable[P, T]: '''Типобезопасный декоратор для добавления логирования к функции.''' 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: '''Сложение двух чисел.''' return x + y
Без ParamSpec
самым простым способом аннотировать такой шаблон раньше, нужно было использование TypeVar
с привязкой Callable[..., Any]
. Что вызывает две проблемы:
*args
и **kwargs
необходимо ввести Any
.@add_logging()
при возврате внутренней функции может потребоваться cast()
, или необходимо указать средству проверки статического типа игнорировать возвращаемый внутренний результат.ParamSpec.args
:ParamSpec.kwargs
:Так как ParamSpec
фиксирует как позиционные, так и ключевые аргументы, ParamSpec.args
и ParamSpec.kwargs
могут использоваться для разделения ParamSpec
на его компоненты.
ParamSpec.args
представляет кортеж позиционных параметров в данном вызове и должен использоваться только для аннотации *args
. ParamSpec.kwargs
представляет собой сопоставление ключевых аргументов с их значениями в данном вызове и должен использоваться только для аннотирования **kwargs
. Оба атрибута требуют, чтобы аннотированный параметр находился в области действия. Во время выполнения ParamSpec.args
и ParamSpec.kwargs
являются экземплярами ParamSpecArgs
и ParamSpecKwargs
соответственно.
ParamSpec.__name__
:Атрибут ParamSpec.__name__
представляет собой название спецификации параметра.
ParamSpec.__default__
:Добавлено в Python 3.13
Атрибут ParamSpec.__default__
представляет собой значение по умолчанию для переменной типа или typing.NoDefault
, если у нее нет значения по умолчанию.
ParamSpec.has_default()
:Добавлено в Python 3.13
Функция ParamSpec.has_default()
возвращает значение, указывающее, имеет ли переменная типа значение по умолчанию. Это эквивалентно проверке того, не является ли __default__
синглтоном typing.NoDefault
, за исключением того, что не приводит к принудительному лениво вычисляемого значения по умолчанию.
Переменные спецификации параметров, созданные с помощью covariant=True
или contravariant=True
, можно использовать для объявления ковариантных или контравариантных универсальных типов. Также допускается связанный аргумент bound
, аналогичный typing.TypeVar
. Однако фактическая семантика этих ключевых слов еще не определена.
Переменная спецификации параметра сообщает средству проверки типов, что вызываемый объект, переданный в декоратор, и новый вызываемый объект, возвращаемый им, имеют взаимозависимые параметры типа:
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]: '''Типобезопасный декоратор для добавления логирования к функции.''' def inner(*args: P.args, **kwargs: P.kwargs) -> T: logging.info(f'{f.__name__} был вызван') return f(*args, **kwargs) return inner @add_logging def add_two(x: float, y: float) -> float: '''Сложение двух чисел.''' return x + y
Новое в Python 3.10.