Definition
A ParamSpec represents a callable's positional and keyword parameters as one relationship. It is designed for higher-order functions that forward calls without changing their accepted arguments.
Preserve a decorator signature
from collections.abc import Callable
from functools import wraps
from typing import ParamSpec, TypeVar
P = ParamSpec("P")
R = TypeVar("R")
def traced(function: Callable[P, R]) -> Callable[P, R]:
@wraps(function)
def wrapper(*args: P.args, **kwargs: P.kwargs) -> R:
print("[event] forwarding call to:", function.__name__)
return function(*args, **kwargs)
return wrapper
@traced
def repeat(text: str, count: int = 2) -> str:
return text * count
print("[result] decorated call:", repeat("py", count=3))
P.args and P.kwargs annotate the forwarding implementation. The checker exposes the original repeat parameters to callers instead of reducing the decorator result to an uninformative Callable[..., str].
Use it when
Use ParamSpec when arguments pass through a decorator, callback adapter, or dependency wrapper. If the wrapper intentionally changes the signature, Concatenate or an explicit callback protocol may communicate the transformation more clearly.
Primary sourceOfficial Python documentation ↗