Skip to content

Commit 11276cd

Browse files
bpo-41559: Documentation for PEP 612 (GH-24000)
1 parent 3bf0532 commit 11276cd

File tree

4 files changed

+238
-8
lines changed

4 files changed

+238
-8
lines changed

Doc/library/stdtypes.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4959,6 +4959,11 @@ All parameterized generics implement special read-only attributes.
49594959
(~T,)
49604960

49614961

4962+
.. note::
4963+
A ``GenericAlias`` object with :class:`typing.ParamSpec` parameters may not
4964+
have correct ``__parameters__`` after substitution because
4965+
:class:`typing.ParamSpec` is intended primarily for static type checking.
4966+
49624967
.. seealso::
49634968

49644969
* :pep:`585` -- "Type Hinting Generics In Standard Collections"

Doc/library/typing.rst

Lines changed: 203 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@
1818
--------------
1919

2020
This module provides runtime support for type hints as specified by
21-
:pep:`484`, :pep:`526`, :pep:`544`, :pep:`586`, :pep:`589`, :pep:`591`, and :pep:`613`.
21+
:pep:`484`, :pep:`526`, :pep:`544`, :pep:`586`, :pep:`589`, :pep:`591`,
22+
:pep:`612` and :pep:`613`.
2223
The most fundamental support consists of the types :data:`Any`, :data:`Union`,
2324
:data:`Tuple`, :data:`Callable`, :class:`TypeVar`, and
2425
:class:`Generic`. For full specification please see :pep:`484`. For
@@ -171,6 +172,22 @@ It is possible to declare the return type of a callable without specifying
171172
the call signature by substituting a literal ellipsis
172173
for the list of arguments in the type hint: ``Callable[..., ReturnType]``.
173174

175+
Callables which take other callables as arguments may indicate that their
176+
parameter types are dependent on each other using :class:`ParamSpec`.
177+
Additionally, if that callable adds or removes arguments from other
178+
callables, the :data:`Concatenate` operator may be used. They
179+
take the form ``Callable[ParamSpecVariable, ReturnType]`` and
180+
``Callable[Concatenate[Arg1Type, Arg2Type, ..., ParamSpecVariable], ReturnType]``
181+
respectively.
182+
183+
.. versionchanged:: 3.10
184+
``Callable`` now supports :class:`ParamSpec` and :data:`Concatenate`.
185+
See :pep:`612` for more information.
186+
187+
.. seealso::
188+
The documentation for :class:`ParamSpec` and :class:`Concatenate` provide
189+
examples of usage in ``Callable``.
190+
174191
.. _generics:
175192

176193
Generics
@@ -316,6 +333,43 @@ User defined generic type aliases are also supported. Examples::
316333
.. versionchanged:: 3.7
317334
:class:`Generic` no longer has a custom metaclass.
318335

336+
User-defined generics for parameter expressions are also supported via parameter
337+
specification variables in the form ``Generic[P]``. The behavior is consistent
338+
with type variables' described above as parameter specification variables are
339+
treated by the typing module as a specialized type variable. The one exception
340+
to this is that a list of types can be used to substitute a :class:`ParamSpec`::
341+
342+
>>> from typing import Generic, ParamSpec, TypeVar
343+
344+
>>> T = TypeVar('T')
345+
>>> P = ParamSpec('P')
346+
347+
>>> class Z(Generic[T, P]): ...
348+
...
349+
>>> Z[int, [dict, float]]
350+
__main__.Z[int, (<class 'dict'>, <class 'float'>)]
351+
352+
353+
Furthermore, a generic with only one parameter specification variable will accept
354+
parameter lists in the forms ``X[[Type1, Type2, ...]]`` and also
355+
``X[Type1, Type2, ...]`` for aesthetic reasons. Internally, the latter is converted
356+
to the former and are thus equivalent::
357+
358+
>>> class X(Generic[P]): ...
359+
...
360+
>>> X[int, str]
361+
__main__.X[(<class 'int'>, <class 'str'>)]
362+
>>> X[[int, str]]
363+
__main__.X[(<class 'int'>, <class 'str'>)]
364+
365+
Do note that generics with :class:`ParamSpec` may not have correct
366+
``__parameters__`` after substitution in some cases because they
367+
are intended primarily for static type checking.
368+
369+
.. versionchanged:: 3.10
370+
:class:`Generic` can now be parameterized over parameter expressions.
371+
See :class:`ParamSpec` and :pep:`612` for more details.
372+
319373
A user-defined generic class can have ABCs as base classes without a metaclass
320374
conflict. Generic metaclasses are not supported. The outcome of parameterizing
321375
generics is cached, and most types in the typing module are hashable and
@@ -602,10 +656,80 @@ These can be used as types in annotations using ``[]``, each having a unique syn
602656
``Callable[..., Any]``, and in turn to
603657
:class:`collections.abc.Callable`.
604658

659+
Callables which take other callables as arguments may indicate that their
660+
parameter types are dependent on each other using :class:`ParamSpec`.
661+
Additionally, if that callable adds or removes arguments from other
662+
callables, the :data:`Concatenate` operator may be used. They
663+
take the form ``Callable[ParamSpecVariable, ReturnType]`` and
664+
``Callable[Concatenate[Arg1Type, Arg2Type, ..., ParamSpecVariable], ReturnType]``
665+
respectively.
666+
605667
.. deprecated:: 3.9
606668
:class:`collections.abc.Callable` now supports ``[]``. See :pep:`585` and
607669
:ref:`types-genericalias`.
608670

671+
.. versionchanged:: 3.10
672+
``Callable`` now supports :class:`ParamSpec` and :data:`Concatenate`.
673+
See :pep:`612` for more information.
674+
675+
.. seealso::
676+
The documentation for :class:`ParamSpec` and :class:`Concatenate` provide
677+
examples of usage with ``Callable``.
678+
679+
.. data:: Concatenate
680+
681+
Used with :data:`Callable` and :class:`ParamSpec` to type annotate a higher
682+
order callable which adds, removes, or transforms parameters of another
683+
callable. Usage is in the form
684+
``Concatenate[Arg1Type, Arg2Type, ..., ParamSpecVariable]``. ``Concatenate``
685+
is currently only valid when used as the first argument to a :data:`Callable`.
686+
The last parameter to ``Concatenate`` must be a :class:`ParamSpec`.
687+
688+
For example, to annotate a decorator ``with_lock`` which provides a
689+
:class:`threading.Lock` to the decorated function, ``Concatenate`` can be
690+
used to indicate that ``with_lock`` expects a callable which takes in a
691+
``Lock`` as the first argument, and returns a callable with a different type
692+
signature. In this case, the :class:`ParamSpec` indicates that the returned
693+
callable's parameter types are dependent on the parameter types of the
694+
callable being passed in::
695+
696+
from collections.abc import Callable
697+
from threading import Lock
698+
from typing import Any, Concatenate, ParamSpec
699+
700+
P = ParamSpec('P')
701+
R = ParamSpec('R')
702+
703+
# Use this lock to ensure that only one thread is executing a function
704+
# at any time.
705+
my_lock = Lock()
706+
707+
def with_lock(f: Callable[Concatenate[Lock, P], R]) -> Callable[P, R]:
708+
'''A type-safe decorator which provides a lock.'''
709+
global my_lock
710+
def inner(*args: P.args, **kwargs: P.kwargs) -> T:
711+
# Provide the lock as the first argument.
712+
return f(my_lock, *args, **kwargs)
713+
return inner
714+
715+
@with_lock
716+
def sum_threadsafe(lock: Lock, numbers: list[float]) -> float:
717+
'''Add a list of numbers together in a thread-safe manner.'''
718+
with lock:
719+
return sum(numbers)
720+
721+
# We don't need to pass in the lock ourselves thanks to the decorator.
722+
sum_threadsafe([1.1, 2.2, 3.3])
723+
724+
.. versionadded:: 3.10
725+
726+
.. seealso::
727+
728+
* :pep:`612` -- Parameter Specification Variables (the PEP which introduced
729+
``ParamSpec`` and ``Concatenate``).
730+
* :class:`ParamSpec` and :class:`Callable`.
731+
732+
609733
.. class:: Type(Generic[CT_co])
610734

611735
A variable annotated with ``C`` may accept a value of type ``C``. In
@@ -876,6 +1000,84 @@ These are not used in annotations. They are building blocks for creating generic
8761000
for the type variable must be a subclass of the boundary type,
8771001
see :pep:`484`.
8781002

1003+
.. class:: ParamSpec(name, *, bound=None, covariant=False, contravariant=False)
1004+
1005+
Parameter specification variable. A specialized version of
1006+
:class:`type variables <TypeVar>`.
1007+
1008+
Usage::
1009+
1010+
P = ParamSpec('P')
1011+
1012+
Parameter specification variables exist primarily for the benefit of static
1013+
type checkers. They are used to forward the parameter types of one
1014+
callable to another callable -- a pattern commonly found in higher order
1015+
functions and decorators. They are only valid when used in ``Concatenate``,
1016+
or as the first argument to ``Callable``, or as parameters for user-defined
1017+
Generics. See :class:`Generic` for more information on generic types.
1018+
1019+
For example, to add basic logging to a function, one can create a decorator
1020+
``add_logging`` to log function calls. The parameter specification variable
1021+
tells the type checker that the callable passed into the decorator and the
1022+
new callable returned by it have inter-dependent type parameters::
1023+
1024+
from collections.abc import Callable
1025+
from typing import TypeVar, ParamSpec
1026+
import logging
1027+
1028+
T = TypeVar('T')
1029+
P = ParamSpec('P')
1030+
1031+
def add_logging(f: Callable[P, T]) -> Callable[P, T]:
1032+
'''A type-safe decorator to add logging to a function.'''
1033+
def inner(*args: P.args, **kwargs: P.kwargs) -> T:
1034+
logging.info(f'{f.__name__} was called')
1035+
return f(*args, **kwargs)
1036+
return inner
1037+
1038+
@add_logging
1039+
def add_two(x: float, y: float) -> float:
1040+
'''Add two numbers together.'''
1041+
return x + y
1042+
1043+
Without ``ParamSpec``, the simplest way to annotate this previously was to
1044+
use a :class:`TypeVar` with bound ``Callable[..., Any]``. However this
1045+
causes two problems:
1046+
1047+
1. The type checker can't type check the ``inner`` function because
1048+
``*args`` and ``**kwargs`` have to be typed :data:`Any`.
1049+
2. :func:`~cast` may be required in the body of the ``add_logging``
1050+
decorator when returning the ``inner`` function, or the static type
1051+
checker must be told to ignore the ``return inner``.
1052+
1053+
.. attribute:: args
1054+
.. attribute:: kwargs
1055+
1056+
Since ``ParamSpec`` captures both positional and keyword parameters,
1057+
``P.args`` and ``P.kwargs`` can be used to split a ``ParamSpec`` into its
1058+
components. ``P.args`` represents the tuple of positional parameters in a
1059+
given call and should only be used to annotate ``*args``. ``P.kwargs``
1060+
represents the mapping of keyword parameters to their values in a given call,
1061+
and should be only be used to annotate ``**kwargs`` or ``**kwds``. Both
1062+
attributes require the annotated parameter to be in scope.
1063+
1064+
Parameter specification variables created with ``covariant=True`` or
1065+
``contravariant=True`` can be used to declare covariant or contravariant
1066+
generic types. The ``bound`` argument is also accepted, similar to
1067+
:class:`TypeVar`. However the actual semantics of these keywords are yet to
1068+
be decided.
1069+
1070+
.. versionadded:: 3.10
1071+
1072+
.. note::
1073+
Only parameter specification variables defined in global scope can
1074+
be pickled.
1075+
1076+
.. seealso::
1077+
* :pep:`612` -- Parameter Specification Variables (the PEP which introduced
1078+
``ParamSpec`` and ``Concatenate``).
1079+
* :class:`Callable` and :class:`Concatenate`.
1080+
8791081
.. data:: AnyStr
8801082

8811083
``AnyStr`` is a type variable defined as

Doc/whatsnew/3.10.rst

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,28 @@ See :pep:`604` for more details.
144144

145145
(Contributed by Maggie Moss and Philippe Prados in :issue:`41428`.)
146146

147+
PEP 612: Parameter Specification Variables
148+
------------------------------------------
149+
150+
Two new options to improve the information provided to static type checkers for
151+
:pep:`484`\ 's ``Callable`` have been added to the :mod:`typing` module.
152+
153+
The first is the parameter specification variable. They are used to forward the
154+
parameter types of one callable to another callable -- a pattern commonly
155+
found in higher order functions and decorators. Examples of usage can be found
156+
in :class:`typing.ParamSpec`. Previously, there was no easy way to type annotate
157+
dependency of parameter types in such a precise manner.
158+
159+
The second option is the new ``Concatenate`` operator. It's used in conjunction
160+
with parameter specification variables to type annotate a higher order callable
161+
which adds or removes parameters of another callable. Examples of usage can
162+
be found in :class:`typing.Concatenate`.
163+
164+
See :class:`typing.Callable`, :class:`typing.ParamSpec`,
165+
:class:`typing.Concatenate` and :pep:`612` for more details.
166+
167+
(Contributed by Ken Jin in :issue:`41559`.)
168+
147169
Other Language Changes
148170
======================
149171

Lib/typing.py

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -544,8 +544,9 @@ def TypeAlias(self, parameters):
544544

545545
@_SpecialForm
546546
def Concatenate(self, parameters):
547-
"""Used in conjunction with ParamSpec and Callable to represent a higher
548-
order function which adds, removes or transforms parameters of a Callable.
547+
"""Used in conjunction with ``ParamSpec`` and ``Callable`` to represent a
548+
higher order function which adds, removes or transforms parameters of a
549+
callable.
549550
550551
For example::
551552
@@ -735,11 +736,11 @@ class ParamSpec(_Final, _Immutable, _TypeVarLike, _root=True):
735736
736737
Parameter specification variables exist primarily for the benefit of static
737738
type checkers. They are used to forward the parameter types of one
738-
Callable to another Callable, a pattern commonly found in higher order
739-
functions and decorators. They are only valid when used in Concatenate, or
740-
as the first argument to Callable, or as parameters for user-defined Generics.
741-
See class Generic for more information on generic types. An example for
742-
annotating a decorator::
739+
callable to another callable, a pattern commonly found in higher order
740+
functions and decorators. They are only valid when used in ``Concatenate``,
741+
or s the first argument to ``Callable``, or as parameters for user-defined
742+
Generics. See class Generic for more information on generic types. An
743+
example for annotating a decorator::
743744
744745
T = TypeVar('T')
745746
P = ParamSpec('P')

0 commit comments

Comments
 (0)