gh-103921: Document PEP 695 (#104642)

Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
This commit is contained in:
Jelle Zijlstra 2023-05-26 10:48:17 -07:00 committed by GitHub
parent 95f1b1fef7
commit 060277d96b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 1240 additions and 308 deletions

View File

@ -917,6 +917,25 @@ Statements
type_ignores=[]) type_ignores=[])
.. class:: TypeAlias(name, type_params, value)
A :ref:`type alias <type-aliases>` created through the :keyword:`type`
statement. ``name`` is the name of the alias, ``type_params`` is a list of
:ref:`type parameters <ast-type-params>`, and ``value`` is the value of the
type alias.
.. doctest::
>>> print(ast.dump(ast.parse('type Alias = int'), indent=4))
Module(
body=[
TypeAlias(
name=Name(id='Alias', ctx=Store()),
type_params=[],
value=Name(id='int', ctx=Load()))],
type_ignores=[])
Other statements which are only applicable inside functions or loops are Other statements which are only applicable inside functions or loops are
described in other sections. described in other sections.
@ -1644,15 +1663,93 @@ Pattern matching
value=Constant(value=Ellipsis))])])], value=Constant(value=Ellipsis))])])],
type_ignores=[]) type_ignores=[])
.. _ast-type-params:
Type parameters
^^^^^^^^^^^^^^^
:ref:`Type parameters <type-params>` can exist on classes, functions, and type
aliases.
.. class:: TypeVar(name, bound)
A :class:`typing.TypeVar`. ``name`` is the name of the type variable.
``bound`` is the bound or constraints, if any. If ``bound`` is a :class:`Tuple`,
it represents constraints; otherwise it represents the bound.
.. doctest::
>>> print(ast.dump(ast.parse("type Alias[T: int] = list[T]"), indent=4))
Module(
body=[
TypeAlias(
name=Name(id='Alias', ctx=Store()),
type_params=[
TypeVar(
name='T',
bound=Name(id='int', ctx=Load()))],
value=Subscript(
value=Name(id='list', ctx=Load()),
slice=Name(id='T', ctx=Load()),
ctx=Load()))],
type_ignores=[])
.. class:: ParamSpec(name)
A :class:`typing.ParamSpec`. ``name`` is the name of the parameter specification.
.. doctest::
>>> print(ast.dump(ast.parse("type Alias[**P] = Callable[P, int]"), indent=4))
Module(
body=[
TypeAlias(
name=Name(id='Alias', ctx=Store()),
type_params=[
ParamSpec(name='P')],
value=Subscript(
value=Name(id='Callable', ctx=Load()),
slice=Tuple(
elts=[
Name(id='P', ctx=Load()),
Name(id='int', ctx=Load())],
ctx=Load()),
ctx=Load()))],
type_ignores=[])
.. class:: TypeVarTuple(name)
A :class:`typing.TypeVarTuple`. ``name`` is the name of the type variable tuple.
.. doctest::
>>> print(ast.dump(ast.parse("type Alias[*Ts] = tuple[*Ts]"), indent=4))
Module(
body=[
TypeAlias(
name=Name(id='Alias', ctx=Store()),
type_params=[
TypeVarTuple(name='Ts')],
value=Subscript(
value=Name(id='tuple', ctx=Load()),
slice=Tuple(
elts=[
Starred(
value=Name(id='Ts', ctx=Load()),
ctx=Load())],
ctx=Load()),
ctx=Load()))],
type_ignores=[])
Function and class definitions Function and class definitions
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. class:: FunctionDef(name, args, body, decorator_list, returns, type_comment) .. class:: FunctionDef(name, type_params, args, body, decorator_list, returns, type_comment)
A function definition. A function definition.
* ``name`` is a raw string of the function name. * ``name`` is a raw string of the function name.
* ``type_params`` is a list of :ref:`type parameters <ast-type-params>`.
* ``args`` is an :class:`arguments` node. * ``args`` is an :class:`arguments` node.
* ``body`` is the list of nodes inside the function. * ``body`` is the list of nodes inside the function.
* ``decorator_list`` is the list of decorators to be applied, stored outermost * ``decorator_list`` is the list of decorators to be applied, stored outermost
@ -1820,11 +1917,12 @@ Function and class definitions
type_ignores=[]) type_ignores=[])
.. class:: ClassDef(name, bases, keywords, body, decorator_list) .. class:: ClassDef(name, type_params, bases, keywords, body, decorator_list)
A class definition. A class definition.
* ``name`` is a raw string for the class name * ``name`` is a raw string for the class name
* ``type_params`` is a list of :ref:`type parameters <ast-type-params>`.
* ``bases`` is a list of nodes for explicitly specified base classes. * ``bases`` is a list of nodes for explicitly specified base classes.
* ``keywords`` is a list of :class:`keyword` nodes, principally for 'metaclass'. * ``keywords`` is a list of :class:`keyword` nodes, principally for 'metaclass'.
Other keywords will be passed to the metaclass, as per `PEP-3115 Other keywords will be passed to the metaclass, as per `PEP-3115

View File

@ -188,9 +188,9 @@ operation is being performed, so the intermediate analysis object isn't useful:
For a module, it disassembles all functions. For a class, it disassembles For a module, it disassembles all functions. For a class, it disassembles
all methods (including class and static methods). For a code object or all methods (including class and static methods). For a code object or
sequence of raw bytecode, it prints one line per bytecode instruction. sequence of raw bytecode, it prints one line per bytecode instruction.
It also recursively disassembles nested code objects (the code of It also recursively disassembles nested code objects. These can include
comprehensions, generator expressions and nested functions, and the code generator expressions, nested functions, the bodies of nested classes,
used for building nested classes). and the code objects used for :ref:`annotation scopes <annotation-scopes>`.
Strings are first compiled to code objects with the :func:`compile` Strings are first compiled to code objects with the :func:`compile`
built-in function before being disassembled. If no object is provided, this built-in function before being disassembled. If no object is provided, this
function disassembles the last traceback. function disassembles the last traceback.
@ -926,6 +926,27 @@ iterations of the loop.
.. opcode:: LOAD_NAME (namei) .. opcode:: LOAD_NAME (namei)
Pushes the value associated with ``co_names[namei]`` onto the stack. Pushes the value associated with ``co_names[namei]`` onto the stack.
The name is looked up within the locals, then the globals, then the builtins.
.. opcode:: LOAD_LOCALS
Pushes a reference to the locals dictionary onto the stack. This is used
to prepare namespace dictionaries for :opcode:`LOAD_FROM_DICT_OR_DEREF`
and :opcode:`LOAD_FROM_DICT_OR_GLOBALS`.
.. versionadded:: 3.12
.. opcode:: LOAD_FROM_DICT_OR_GLOBALS (i)
Pops a mapping off the stack and looks up the value for ``co_names[namei]``.
If the name is not found there, looks it up in the globals and then the builtins,
similar to :opcode:`LOAD_GLOBAL`.
This is used for loading global variables in
:ref:`annotation scopes <annotation-scopes>` within class bodies.
.. versionadded:: 3.12
.. opcode:: BUILD_TUPLE (count) .. opcode:: BUILD_TUPLE (count)
@ -1243,16 +1264,17 @@ iterations of the loop.
``i`` is no longer offset by the length of ``co_varnames``. ``i`` is no longer offset by the length of ``co_varnames``.
.. opcode:: LOAD_CLASSDEREF (i) .. opcode:: LOAD_FROM_DICT_OR_DEREF (i)
Much like :opcode:`LOAD_DEREF` but first checks the locals dictionary before Pops a mapping off the stack and looks up the name associated with
consulting the cell. This is used for loading free variables in class slot ``i`` of the "fast locals" storage in this mapping.
bodies. If the name is not found there, loads it from the cell contained in
slot ``i``, similar to :opcode:`LOAD_DEREF`. This is used for loading
free variables in class bodies (which previously used
:opcode:`!LOAD_CLASSDEREF`) and in
:ref:`annotation scopes <annotation-scopes>` within class bodies.
.. versionadded:: 3.4 .. versionadded:: 3.12
.. versionchanged:: 3.11
``i`` is no longer offset by the length of ``co_varnames``.
.. opcode:: STORE_DEREF (i) .. opcode:: STORE_DEREF (i)
@ -1504,13 +1526,45 @@ iterations of the loop.
The operand determines which intrinsic function is called: The operand determines which intrinsic function is called:
* ``0`` Not valid +-----------------------------------+-----------------------------------+
* ``1`` Prints the argument to standard out. Used in the REPL. | Operand | Description |
* ``2`` Performs ``import *`` for the named module. +===================================+===================================+
* ``3`` Extracts the return value from a ``StopIteration`` exception. | ``INTRINSIC_1_INVALID`` | Not valid |
* ``4`` Wraps an aync generator value +-----------------------------------+-----------------------------------+
* ``5`` Performs the unary ``+`` operation | ``INTRINSIC_PRINT`` | Prints the argument to standard |
* ``6`` Converts a list to a tuple | | out. Used in the REPL. |
+-----------------------------------+-----------------------------------+
| ``INTRINSIC_IMPORT_STAR`` | Performs ``import *`` for the |
| | named module. |
+-----------------------------------+-----------------------------------+
| ``INTRINSIC_STOPITERATION_ERROR`` | Extracts the return value from a |
| | ``StopIteration`` exception. |
+-----------------------------------+-----------------------------------+
| ``INTRINSIC_ASYNC_GEN_WRAP`` | Wraps an aync generator value |
+-----------------------------------+-----------------------------------+
| ``INTRINSIC_UNARY_POSITIVE`` | Performs the unary ``+`` |
| | operation |
+-----------------------------------+-----------------------------------+
| ``INTRINSIC_LIST_TO_TUPLE`` | Converts a list to a tuple |
+-----------------------------------+-----------------------------------+
| ``INTRINSIC_TYPEVAR`` | Creates a :class:`typing.TypeVar` |
+-----------------------------------+-----------------------------------+
| ``INTRINSIC_PARAMSPEC`` | Creates a |
| | :class:`typing.ParamSpec` |
+-----------------------------------+-----------------------------------+
| ``INTRINSIC_TYPEVARTUPLE`` | Creates a |
| | :class:`typing.TypeVarTuple` |
+-----------------------------------+-----------------------------------+
| ``INTRINSIC_SUBSCRIPT_GENERIC`` | Returns :class:`typing.Generic` |
| | subscripted with the argument |
+-----------------------------------+-----------------------------------+
| ``INTRINSIC_TYPEALIAS`` | Creates a |
| | :class:`typing.TypeAliasType`; |
| | used in the :keyword:`type` |
| | statement. The argument is a tuple|
| | of the type alias's name, |
| | type parameters, and value. |
+-----------------------------------+-----------------------------------+
.. versionadded:: 3.12 .. versionadded:: 3.12
@ -1522,8 +1576,25 @@ iterations of the loop.
The operand determines which intrinsic function is called: The operand determines which intrinsic function is called:
* ``0`` Not valid +----------------------------------------+-----------------------------------+
* ``1`` Calculates the :exc:`ExceptionGroup` to raise from a ``try-except*``. | Operand | Description |
+========================================+===================================+
| ``INTRINSIC_2_INVALID`` | Not valid |
+----------------------------------------+-----------------------------------+
| ``INTRINSIC_PREP_RERAISE_STAR`` | Calculates the |
| | :exc:`ExceptionGroup` to raise |
| | from a ``try-except*``. |
+----------------------------------------+-----------------------------------+
| ``INTRINSIC_TYPEVAR_WITH_BOUND`` | Creates a :class:`typing.TypeVar` |
| | with a bound. |
+----------------------------------------+-----------------------------------+
| ``INTRINSIC_TYPEVAR_WITH_CONSTRAINTS`` | Creates a |
| | :class:`typing.TypeVar` with |
| | constraints. |
+----------------------------------------+-----------------------------------+
| ``INTRINSIC_SET_FUNCTION_TYPE_PARAMS`` | Sets the ``__type_params__`` |
| | attribute of a function. |
+----------------------------------------+-----------------------------------+
.. versionadded:: 3.12 .. versionadded:: 3.12

View File

@ -5476,6 +5476,14 @@ types, where they are relevant. Some of these are not reported by the
.. versionadded:: 3.3 .. versionadded:: 3.3
.. attribute:: definition.__type_params__
The :ref:`type parameters <type-params>` of generic classes, functions,
and :ref:`type aliases <type-aliases>`.
.. versionadded:: 3.12
.. attribute:: class.__mro__ .. attribute:: class.__mro__
This attribute is a tuple of classes that are considered when looking for This attribute is a tuple of classes that are considered when looking for

View File

@ -101,6 +101,8 @@ annotations. These include:
* :pep:`692`: Using ``TypedDict`` for more precise ``**kwargs`` typing * :pep:`692`: Using ``TypedDict`` for more precise ``**kwargs`` typing
*Introducing* a new way of typing ``**kwargs`` with :data:`Unpack` and *Introducing* a new way of typing ``**kwargs`` with :data:`Unpack` and
:data:`TypedDict` :data:`TypedDict`
* :pep:`695`: Type Parameter Syntax
*Introducing* builtin syntax for creating generic functions, classes, and type aliases.
* :pep:`698`: Adding an override decorator to typing * :pep:`698`: Adding an override decorator to typing
*Introducing* the :func:`@override<override>` decorator *Introducing* the :func:`@override<override>` decorator
@ -109,10 +111,12 @@ annotations. These include:
Type aliases Type aliases
============ ============
A type alias is defined by assigning the type to the alias. In this example, A type alias is defined using the :keyword:`type` statement, which creates
``Vector`` and ``list[float]`` will be treated as interchangeable synonyms:: an instance of :class:`TypeAliasType`. In this example,
``Vector`` and ``list[float]`` will be treated equivalently by static type
checkers::
Vector = list[float] type Vector = list[float]
def scale(scalar: float, vector: Vector) -> Vector: def scale(scalar: float, vector: Vector) -> Vector:
return [scalar * num for num in vector] return [scalar * num for num in vector]
@ -124,9 +128,9 @@ Type aliases are useful for simplifying complex type signatures. For example::
from collections.abc import Sequence from collections.abc import Sequence
ConnectionOptions = dict[str, str] type ConnectionOptions = dict[str, str]
Address = tuple[str, int] type Address = tuple[str, int]
Server = tuple[Address, ConnectionOptions] type Server = tuple[Address, ConnectionOptions]
def broadcast_message(message: str, servers: Sequence[Server]) -> None: def broadcast_message(message: str, servers: Sequence[Server]) -> None:
... ...
@ -141,6 +145,18 @@ Type aliases are useful for simplifying complex type signatures. For example::
Note that ``None`` as a type hint is a special case and is replaced by Note that ``None`` as a type hint is a special case and is replaced by
``type(None)``. ``type(None)``.
The :keyword:`type` statement is new in Python 3.12. For backwards
compatibility, type aliases can also be created through simple assignment::
Vector = list[float]
Or marked with :data:`TypeAlias` to make it explicit that this is a type alias,
not a normal variable assignment::
from typing import TypeAlias
Vector: TypeAlias = list[float]
.. _distinct: .. _distinct:
NewType NewType
@ -206,7 +222,7 @@ See :pep:`484` for more details.
.. note:: .. note::
Recall that the use of a type alias declares two types to be *equivalent* to Recall that the use of a type alias declares two types to be *equivalent* to
one another. Doing ``Alias = Original`` will make the static type checker one another. Doing ``type Alias = Original`` will make the static type checker
treat ``Alias`` as being *exactly equivalent* to ``Original`` in all cases. treat ``Alias`` as being *exactly equivalent* to ``Original`` in all cases.
This is useful when you want to simplify complex type signatures. This is useful when you want to simplify complex type signatures.
@ -282,19 +298,26 @@ subscription to denote expected types for container elements.
def notify_by_email(employees: Sequence[Employee], def notify_by_email(employees: Sequence[Employee],
overrides: Mapping[str, str]) -> None: ... overrides: Mapping[str, str]) -> None: ...
Generics can be parameterized by using a factory available in typing Generics can be parameterized by using :ref:`type parameter syntax <type-params>`::
called :class:`TypeVar`.
:: from collections.abc import Sequence
def first[T](l: Sequence[T]) -> T: # Generic function
return l[0]
Or by using the :class:`TypeVar` factory directly::
from collections.abc import Sequence from collections.abc import Sequence
from typing import TypeVar from typing import TypeVar
T = TypeVar('T') # Declare type variable U = TypeVar('U') # Declare type variable
def first(l: Sequence[T]) -> T: # Generic function def first(l: Sequence[U]) -> U: # Generic function
return l[0] return l[0]
.. versionchanged:: 3.12
Syntactic support for generics is new in Python 3.12.
.. _user-defined-generics: .. _user-defined-generics:
User-defined generic types User-defined generic types
@ -304,12 +327,9 @@ A user-defined class can be defined as a generic class.
:: ::
from typing import TypeVar, Generic
from logging import Logger from logging import Logger
T = TypeVar('T') class LoggedVar[T]:
class LoggedVar(Generic[T]):
def __init__(self, value: T, name: str, logger: Logger) -> None: def __init__(self, value: T, name: str, logger: Logger) -> None:
self.name = name self.name = name
self.logger = logger self.logger = logger
@ -326,12 +346,23 @@ A user-defined class can be defined as a generic class.
def log(self, message: str) -> None: def log(self, message: str) -> None:
self.logger.info('%s: %s', self.name, message) self.logger.info('%s: %s', self.name, message)
``Generic[T]`` as a base class defines that the class ``LoggedVar`` takes a This syntax indicates that the class ``LoggedVar`` is parameterised around a
single type parameter ``T`` . This also makes ``T`` valid as a type within the single :class:`type variable <TypeVar>` ``T`` . This also makes ``T`` valid as
class body. a type within the class body.
The :class:`Generic` base class defines :meth:`~object.__class_getitem__` so Generic classes implicitly inherit from :class:`Generic`. For compatibility
that ``LoggedVar[T]`` is valid as a type:: with Python 3.11 and lower, it is also possible to inherit explicitly from
:class:`Generic` to indicate a generic class::
from typing import TypeVar, Generic
T = TypeVar('T')
class LoggedVar(Generic[T]):
...
Generic classes have :meth:`~object.__class_getitem__` methods, meaning they
can be parameterised at runtime (e.g. ``LoggedVar[int]`` below)::
from collections.abc import Iterable from collections.abc import Iterable
@ -344,11 +375,14 @@ A generic type can have any number of type variables. All varieties of
from typing import TypeVar, Generic, Sequence from typing import TypeVar, Generic, Sequence
T = TypeVar('T', contravariant=True) class WeirdTrio[T, B: Sequence[bytes], S: (int, str)]:
B = TypeVar('B', bound=Sequence[bytes], covariant=True) ...
S = TypeVar('S', int, str)
class WeirdTrio(Generic[T, B, S]): OldT = TypeVar('OldT', contravariant=True)
OldB = TypeVar('OldB', bound=Sequence[bytes], covariant=True)
OldS = TypeVar('OldS', int, str)
class OldWeirdTrio(Generic[OldT, OldB, OldS]):
... ...
Each type variable argument to :class:`Generic` must be distinct. Each type variable argument to :class:`Generic` must be distinct.
@ -357,29 +391,26 @@ This is thus invalid::
from typing import TypeVar, Generic from typing import TypeVar, Generic
... ...
class Pair[M, M]: # SyntaxError
...
T = TypeVar('T') T = TypeVar('T')
class Pair(Generic[T, T]): # INVALID class Pair(Generic[T, T]): # INVALID
... ...
You can use multiple inheritance with :class:`Generic`:: Generic classes can also inherit from other classes::
from collections.abc import Sized from collections.abc import Sized
from typing import TypeVar, Generic
T = TypeVar('T') class LinkedList[T](Sized):
class LinkedList(Sized, Generic[T]):
... ...
When inheriting from generic classes, some type variables could be fixed:: When inheriting from generic classes, some type parameters could be fixed::
from collections.abc import Mapping from collections.abc import Mapping
from typing import TypeVar
T = TypeVar('T') class MyDict[T](Mapping[str, T]):
class MyDict(Mapping[str, T]):
... ...
In this case ``MyDict`` has a single parameter, ``T``. In this case ``MyDict`` has a single parameter, ``T``.
@ -392,49 +423,66 @@ not generic but implicitly inherits from ``Iterable[Any]``::
class MyIterable(Iterable): # Same as Iterable[Any] class MyIterable(Iterable): # Same as Iterable[Any]
User defined generic type aliases are also supported. Examples:: User-defined generic type aliases are also supported. Examples::
from collections.abc import Iterable from collections.abc import Iterable
from typing import TypeVar
S = TypeVar('S') type Response[S] = Iterable[S] | int
Response = Iterable[S] | int
# Return type here is same as Iterable[str] | int # Return type here is same as Iterable[str] | int
def response(query: str) -> Response[str]: def response(query: str) -> Response[str]:
... ...
T = TypeVar('T', int, float, complex) type Vec[T] = Iterable[tuple[T, T]]
Vec = Iterable[tuple[T, T]]
def inproduct(v: Vec[T]) -> T: # Same as Iterable[tuple[T, T]] def inproduct[T: (int, float, complex)](v: Vec[T]) -> T: # Same as Iterable[tuple[T, T]]
return sum(x*y for x, y in v) return sum(x*y for x, y in v)
For backward compatibility, generic type aliases can also be created
through a simple assignment::
from collections.abc import Iterable
from typing import TypeVar
S = TypeVar("S")
Response = Iterable[S] | int
.. versionchanged:: 3.7 .. versionchanged:: 3.7
:class:`Generic` no longer has a custom metaclass. :class:`Generic` no longer has a custom metaclass.
.. versionchanged:: 3.12
Syntactic support for generics and type aliases is new in version 3.12.
Previously, generic classes had to explicitly inherit from :class:`Generic`
or contain a type variable in one of their bases.
User-defined generics for parameter expressions are also supported via parameter User-defined generics for parameter expressions are also supported via parameter
specification variables in the form ``Generic[P]``. The behavior is consistent specification variables in the form ``[**P]``. The behavior is consistent
with type variables' described above as parameter specification variables are with type variables' described above as parameter specification variables are
treated by the typing module as a specialized type variable. The one exception treated by the typing module as a specialized type variable. The one exception
to this is that a list of types can be used to substitute a :class:`ParamSpec`:: to this is that a list of types can be used to substitute a :class:`ParamSpec`::
>>> from typing import Generic, ParamSpec, TypeVar >>> class Z[T, **P]: ... # T is a TypeVar; P is a ParamSpec
>>> T = TypeVar('T')
>>> P = ParamSpec('P')
>>> class Z(Generic[T, P]): ...
... ...
>>> Z[int, [dict, float]] >>> Z[int, [dict, float]]
__main__.Z[int, [dict, float]] __main__.Z[int, [dict, float]]
Classes generic over a :class:`ParamSpec` can also be created using explicit
inheritance from :class:`Generic`. In this case, ``**`` is not used::
Furthermore, a generic with only one parameter specification variable will accept from typing import ParamSpec, Generic
P = ParamSpec('P')
class Z(Generic[P]):
...
Another difference between :class:`TypeVar` and :class:`ParamSpec` is that a
generic with only one parameter specification variable will accept
parameter lists in the forms ``X[[Type1, Type2, ...]]`` and also parameter lists in the forms ``X[[Type1, Type2, ...]]`` and also
``X[Type1, Type2, ...]`` for aesthetic reasons. Internally, the latter is converted ``X[Type1, Type2, ...]`` for aesthetic reasons. Internally, the latter is converted
to the former, so the following are equivalent:: to the former, so the following are equivalent::
>>> class X(Generic[P]): ... >>> class X[**P]: ...
... ...
>>> X[int, str] >>> X[int, str]
__main__.X[[int, str]] __main__.X[[int, str]]
@ -767,6 +815,15 @@ These can be used as types in annotations and do not support ``[]``.
.. versionadded:: 3.10 .. versionadded:: 3.10
.. deprecated:: 3.12
:data:`TypeAlias` is deprecated in favor of the :keyword:`type` statement,
which creates instances of :class:`TypeAliasType`.
Note that while :data:`TypeAlias` and :class:`TypeAliasType` serve
similar purposes and have similar names, they are distinct and the
latter is not the type of the former.
Removal of :data:`TypeAlias` is not currently planned, but users
are encouraged to migrate to :keyword:`type` statements.
Special forms Special forms
""""""""""""" """""""""""""
@ -1266,40 +1323,80 @@ These can be used as types in annotations using ``[]``, each having a unique syn
.. versionadded:: 3.11 .. versionadded:: 3.11
Building generic types Building generic types and type aliases
"""""""""""""""""""""" """""""""""""""""""""""""""""""""""""""
These are not used in annotations. They are building blocks for creating generic types. The following objects are not used directly in annotations. Instead, they are building blocks
for creating generic types and type aliases.
These objects can be created through special syntax
(:ref:`type parameter lists <type-params>` and the :keyword:`type` statement).
For compatibility with Python 3.11 and earlier, they can also be created
without the dedicated syntax, as documented below.
.. class:: Generic .. class:: Generic
Abstract base class for generic types. Abstract base class for generic types.
A generic type is typically declared by inheriting from an A generic type is typically declared by adding a list of type parameters
instantiation of this class with one or more type variables. after the class name::
For example, a generic mapping type might be defined as::
class Mapping[KT, VT]:
def __getitem__(self, key: KT) -> VT:
...
# Etc.
Such a class implicitly inherits from ``Generic``.
The runtime semantics of this syntax are discussed in the
:ref:`Language Reference <generic-classes>`.
This class can then be used as follows::
def lookup_name[X, Y](mapping: Mapping[X, Y], key: X, default: Y) -> Y:
try:
return mapping[key]
except KeyError:
return default
Here the brackets after the function name indicate a
:ref:`generic function <generic-functions>`.
For backwards compatibility, generic classes can also be
declared by explicitly inheriting from
``Generic``. In this case, the type parameters must be declared
separately::
KT = TypeVar('KT')
VT = TypeVar('VT')
class Mapping(Generic[KT, VT]): class Mapping(Generic[KT, VT]):
def __getitem__(self, key: KT) -> VT: def __getitem__(self, key: KT) -> VT:
... ...
# Etc. # Etc.
This class can then be used as follows:: .. class:: TypeVar(name, *constraints, bound=None, covariant=False, contravariant=False, infer_variance=False)
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:: TypeVar
Type variable. Type variable.
Usage:: The preferred way to construct a type variable is via the dedicated syntax
for :ref:`generic functions <generic-functions>`,
:ref:`generic classes <generic-classes>`, and
:ref:`generic type aliases <generic-type-aliases>`::
class Sequence[T]: # T is a TypeVar
...
This syntax can also be used to create bound and constrained type
variables::
class StrSequence[S: str]: # S is a TypeVar bound to str
...
class StrOrBytesSequence[A: (str, bytes)]: # A is a TypeVar constrained to str or bytes
...
However, if desired, reusable type variables can also be constructed manually, like so::
T = TypeVar('T') # Can be anything T = TypeVar('T') # Can be anything
S = TypeVar('S', bound=str) # Can be any subtype of str S = TypeVar('S', bound=str) # Can be any subtype of str
@ -1307,27 +1404,36 @@ These are not used in annotations. They are building blocks for creating generic
Type variables exist primarily for the benefit of static type Type variables exist primarily for the benefit of static type
checkers. They serve as the parameters for generic types as well checkers. They serve as the parameters for generic types as well
as for generic function definitions. See :class:`Generic` for more as for generic function and type alias definitions.
See :class:`Generic` for more
information on generic types. Generic functions work as follows:: information on generic types. Generic functions work as follows::
def repeat(x: T, n: int) -> Sequence[T]: def repeat[T](x: T, n: int) -> Sequence[T]:
"""Return a list containing n references to x.""" """Return a list containing n references to x."""
return [x]*n return [x]*n
def print_capitalized(x: S) -> S: def print_capitalized[S: str](x: S) -> S:
"""Print x capitalized, and return x.""" """Print x capitalized, and return x."""
print(x.capitalize()) print(x.capitalize())
return x return x
def concatenate(x: A, y: A) -> A: def concatenate[A: (str, bytes)](x: A, y: A) -> A:
"""Add two strings or bytes objects together.""" """Add two strings or bytes objects together."""
return x + y return x + y
Note that type variables can be *bound*, *constrained*, or neither, but Note that type variables can be *bound*, *constrained*, or neither, but
cannot be both bound *and* constrained. cannot be both bound *and* constrained.
The variance of type variables is inferred by type checkers when they are created
through the :ref:`type parameter syntax <type-params>` or when
``infer_variance=True`` is passed.
Manually created type variables may be explicitly marked covariant or contravariant by passing
``covariant=True`` or ``contravariant=True``.
By default, manually created type variables are invariant.
See :pep:`484` and :pep:`695` for more details.
Bound type variables and constrained type variables have different Bound type variables and constrained type variables have different
semantics in several important ways. Using a *bound* type variable means semantics in several important ways. Using a *bound* type variable means
that the ``TypeVar`` will be solved using the most specific type possible:: that the ``TypeVar`` will be solved using the most specific type possible::
@ -1346,6 +1452,10 @@ These are not used in annotations. They are building blocks for creating generic
Type variables can be bound to concrete types, abstract types (ABCs or Type variables can be bound to concrete types, abstract types (ABCs or
protocols), and even unions of types:: protocols), and even unions of types::
# Can be anything with an __abs__ method
def print_abs[T: SupportsAbs](arg: T) -> None:
print("Absolute value:", abs(arg))
U = TypeVar('U', bound=str|bytes) # Can be any subtype of the union str|bytes 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 V = TypeVar('V', bound=SupportsAbs) # Can be anything with an __abs__ method
@ -1362,29 +1472,76 @@ These are not used in annotations. They are building blocks for creating generic
c = concatenate('one', b'two') # error: type variable 'A' can be either str or bytes in a function call, but not both c = concatenate('one', b'two') # error: type variable 'A' can be either str or bytes in a function call, but not both
At runtime, ``isinstance(x, T)`` will raise :exc:`TypeError`. In general, At runtime, ``isinstance(x, T)`` will raise :exc:`TypeError`.
:func:`isinstance` and :func:`issubclass` should not be used with types.
Type variables may be marked covariant or contravariant by passing .. attribute:: __name__
``covariant=True`` or ``contravariant=True``. See :pep:`484` for more
details. By default, type variables are invariant.
.. class:: TypeVarTuple The name of the type variable.
.. attribute:: __covariant__
Whether the type var has been explicitly marked as covariant.
.. attribute:: __contravariant__
Whether the type var has been explicitly marked as contravariant.
.. attribute:: __infer_variance__
Whether the type variable's variance should be inferred by type checkers.
.. versionadded:: 3.12
.. attribute:: __bound__
The bound of the type variable, if any.
.. versionchanged:: 3.12
For type variables created through :ref:`type parameter syntax <type-params>`,
the bound is evaluated only when the attribute is accessed, not when
the type variable is created (see :ref:`lazy-evaluation`).
.. attribute:: __constraints__
A tuple containing the constraints of the type variable, if any.
.. versionchanged:: 3.12
For type variables created through :ref:`type parameter syntax <type-params>`,
the constraints are evaluated only when the attribute is accessed, not when
the type variable is created (see :ref:`lazy-evaluation`).
.. versionchanged:: 3.12
Type variables can now be declared using the
:ref:`type parameter <type-params>` syntax introduced by :pep:`695`.
The ``infer_variance`` parameter was added.
.. class:: TypeVarTuple(name)
Type variable tuple. A specialized form of :class:`type variable <TypeVar>` Type variable tuple. A specialized form of :class:`type variable <TypeVar>`
that enables *variadic* generics. that enables *variadic* generics.
Type variable tuples can be declared in :ref:`type parameter lists <type-params>`
using a single asterisk (``*``) before the name::
def move_first_element_to_last[T, *Ts](tup: tuple[T, *Ts]) -> tuple[*Ts, T]:
return (*tup[1:], tup[0])
Or by explicitly invoking the ``TypeVarTuple`` constructor::
T = TypeVar("T")
Ts = TypeVarTuple("Ts")
def move_first_element_to_last(tup: tuple[T, *Ts]) -> tuple[*Ts, T]:
return (*tup[1:], tup[0])
A normal type variable enables parameterization with a single type. A type A normal type variable enables parameterization with a single type. A type
variable tuple, in contrast, allows parameterization with an variable tuple, in contrast, allows parameterization with an
*arbitrary* number of types by acting like an *arbitrary* number of type *arbitrary* number of types by acting like an *arbitrary* number of type
variables wrapped in a tuple. For example:: variables wrapped in a tuple. For example::
T = TypeVar('T')
Ts = TypeVarTuple('Ts')
def move_first_element_to_last(tup: tuple[T, *Ts]) -> tuple[*Ts, T]:
return (*tup[1:], tup[0])
# T is bound to int, Ts is bound to () # T is bound to int, Ts is bound to ()
# Return value is (1,), which has type tuple[int] # Return value is (1,), which has type tuple[int]
move_first_element_to_last(tup=(1,)) move_first_element_to_last(tup=(1,))
@ -1420,8 +1577,7 @@ These are not used in annotations. They are building blocks for creating generic
Type variable tuples can be used in the same contexts as normal type Type variable tuples can be used in the same contexts as normal type
variables. For example, in class definitions, arguments, and return types:: variables. For example, in class definitions, arguments, and return types::
Shape = TypeVarTuple('Shape') class Array[*Shape]:
class Array(Generic[*Shape]):
def __getitem__(self, key: tuple[*Shape]) -> float: ... def __getitem__(self, key: tuple[*Shape]) -> float: ...
def __abs__(self) -> "Array[*Shape]": ... def __abs__(self) -> "Array[*Shape]": ...
def get_shape(self) -> tuple[*Shape]: ... def get_shape(self) -> tuple[*Shape]: ...
@ -1430,10 +1586,10 @@ These are not used in annotations. They are building blocks for creating generic
DType = TypeVar('DType') DType = TypeVar('DType')
class Array(Generic[DType, *Shape]): # This is fine class Array[DType, *Shape]: # This is fine
pass pass
class Array2(Generic[*Shape, DType]): # This would also be fine class Array2[*Shape, DType]: # This would also be fine
pass pass
float_array_1d: Array[float, Height] = Array() # Totally fine float_array_1d: Array[float, Height] = Array() # Totally fine
@ -1443,13 +1599,13 @@ These are not used in annotations. They are building blocks for creating generic
list of type arguments or type parameters:: list of type arguments or type parameters::
x: tuple[*Ts, *Ts] # Not valid x: tuple[*Ts, *Ts] # Not valid
class Array(Generic[*Shape, *Shape]): # Not valid class Array[*Shape, *Shape]: # Not valid
pass pass
Finally, an unpacked type variable tuple can be used as the type annotation Finally, an unpacked type variable tuple can be used as the type annotation
of ``*args``:: of ``*args``::
def call_soon( def call_soon[*Ts](
callback: Callable[[*Ts], None], callback: Callable[[*Ts], None],
*args: *Ts *args: *Ts
) -> None: ) -> None:
@ -1465,14 +1621,29 @@ These are not used in annotations. They are building blocks for creating generic
See :pep:`646` for more details on type variable tuples. See :pep:`646` for more details on type variable tuples.
.. attribute:: __name__
The name of the type variable tuple.
.. versionadded:: 3.11 .. versionadded:: 3.11
.. versionchanged:: 3.12
Type variable tuples can now be declared using the
:ref:`type parameter <type-params>` syntax introduced by :pep:`695`.
.. class:: ParamSpec(name, *, bound=None, covariant=False, contravariant=False) .. class:: ParamSpec(name, *, bound=None, covariant=False, contravariant=False)
Parameter specification variable. A specialized version of Parameter specification variable. A specialized version of
:class:`type variables <TypeVar>`. :class:`type variables <TypeVar>`.
Usage:: In :ref:`type parameter lists <type-params>`, parameter specifications
can be declared with two asterisks (``**``)::
type IntFunc[**P] = Callable[P, int]
For compatibility with Python 3.11 and earlier, ``ParamSpec`` objects
can also be created as follows::
P = ParamSpec('P') P = ParamSpec('P')
@ -1489,13 +1660,9 @@ These are not used in annotations. They are building blocks for creating generic
new callable returned by it have inter-dependent type parameters:: new callable returned by it have inter-dependent type parameters::
from collections.abc import Callable from collections.abc import Callable
from typing import TypeVar, ParamSpec
import logging import logging
T = TypeVar('T') def add_logging[T, **P](f: Callable[P, T]) -> Callable[P, T]:
P = ParamSpec('P')
def add_logging(f: Callable[P, T]) -> Callable[P, T]:
'''A type-safe decorator to add logging to a function.''' '''A type-safe decorator to add logging to a function.'''
def inner(*args: P.args, **kwargs: P.kwargs) -> T: def inner(*args: P.args, **kwargs: P.kwargs) -> T:
logging.info(f'{f.__name__} was called') logging.info(f'{f.__name__} was called')
@ -1530,6 +1697,10 @@ These are not used in annotations. They are building blocks for creating generic
``P.args`` and ``P.kwargs`` are instances respectively of ``P.args`` and ``P.kwargs`` are instances respectively of
:class:`ParamSpecArgs` and :class:`ParamSpecKwargs`. :class:`ParamSpecArgs` and :class:`ParamSpecKwargs`.
.. attribute:: __name__
The name of the parameter specification.
Parameter specification variables created with ``covariant=True`` or Parameter specification variables created with ``covariant=True`` or
``contravariant=True`` can be used to declare covariant or contravariant ``contravariant=True`` can be used to declare covariant or contravariant
generic types. The ``bound`` argument is also accepted, similar to generic types. The ``bound`` argument is also accepted, similar to
@ -1538,6 +1709,11 @@ These are not used in annotations. They are building blocks for creating generic
.. versionadded:: 3.10 .. versionadded:: 3.10
.. versionchanged:: 3.12
Parameter specifications can now be declared using the
:ref:`type parameter <type-params>` syntax introduced by :pep:`695`.
.. note:: .. note::
Only parameter specification variables defined in global scope can Only parameter specification variables defined in global scope can
be pickled. be pickled.
@ -1565,6 +1741,67 @@ These are not used in annotations. They are building blocks for creating generic
.. versionadded:: 3.10 .. versionadded:: 3.10
.. class:: TypeAliasType(name, value, *, type_params=())
The type of type aliases created through the :keyword:`type` statement.
Example::
>>> type Alias = int
>>> type(Alias)
<class 'typing.TypeAliasType'>
.. versionadded:: 3.12
.. attribute:: __name__
The name of the type alias::
>>> type Alias = int
>>> Alias.__name__
'Alias'
.. attribute:: __module__
The module in which the type alias was defined::
>>> type Alias = int
>>> Alias.__module__
'__main__'
.. attribute:: __type_params__
The type parameters of the type alias, or an empty tuple if the alias is
not generic:
.. doctest::
>>> type ListOrSet[T] = list[T] | set[T]
>>> ListOrSet.__type_params__
(T,)
>>> type NotGeneric = int
>>> NotGeneric.__type_params__
()
.. attribute:: __value__
The type alias's value. This is :ref:`lazily evaluated <lazy-evaluation>`,
so names used in the definition of the alias are not resolved until the
``__value__`` attribute is accessed:
.. doctest::
>>> type Mutually = Recursive
>>> type Recursive = Mutually
>>> Mutually
Mutually
>>> Recursive
Recursive
>>> Mutually.__value__
Recursive
>>> Recursive.__value__
Mutually
Other special directives Other special directives
"""""""""""""""""""""""" """"""""""""""""""""""""
@ -1613,12 +1850,18 @@ These are not used in annotations. They are building blocks for declaring types.
``NamedTuple`` subclasses can be generic:: ``NamedTuple`` subclasses can be generic::
class Group(NamedTuple, Generic[T]): class Group[T](NamedTuple):
key: T key: T
group: list[T] group: list[T]
Backward-compatible usage:: Backward-compatible usage::
# For creating a generic NamedTuple on Python 3.11 or lower
class Group(NamedTuple, Generic[T]):
key: T
group: list[T]
# A functional syntax is also supported
Employee = NamedTuple('Employee', [('name', str), ('id', int)]) Employee = NamedTuple('Employee', [('name', str), ('id', int)])
.. versionchanged:: 3.6 .. versionchanged:: 3.6
@ -1692,6 +1935,15 @@ These are not used in annotations. They are building blocks for declaring types.
Protocol classes can be generic, for example:: Protocol classes can be generic, for example::
class GenProto[T](Protocol):
def meth(self) -> T:
...
In code that needs to be compatible with Python 3.11 or older, generic
Protocols can be written as follows::
T = TypeVar("T")
class GenProto(Protocol[T]): class GenProto(Protocol[T]):
def meth(self) -> T: def meth(self) -> T:
... ...
@ -1876,6 +2128,13 @@ These are not used in annotations. They are building blocks for declaring types.
A ``TypedDict`` can be generic:: A ``TypedDict`` can be generic::
class Group[T](TypedDict):
key: T
group: list[T]
To create a generic ``TypedDict`` that is compatible with Python 3.11
or lower, inherit from :class:`Generic` explicitly::
class Group(TypedDict, Generic[T]): class Group(TypedDict, Generic[T]):
key: T key: T
group: list[T] group: list[T]
@ -1977,12 +2236,10 @@ Corresponding to built-in types
This type may be used as follows:: This type may be used as follows::
T = TypeVar('T', int, float) def vec2[T: (int, float)](x: T, y: T) -> List[T]:
def vec2(x: T, y: T) -> List[T]:
return [x, y] return [x, y]
def keep_positives(vector: Sequence[T]) -> List[T]: def keep_positives[T: (int, float)](vector: Sequence[T]) -> List[T]:
return [item for item in vector if item > 0] return [item for item in vector if item > 0]
.. deprecated:: 3.9 .. deprecated:: 3.9
@ -2987,3 +3244,5 @@ convenience. This is subject to change, and not all deprecations are listed.
| ``typing.Hashable`` and | 3.12 | Undecided | :gh:`94309` | | ``typing.Hashable`` and | 3.12 | Undecided | :gh:`94309` |
| ``typing.Sized`` | | | | | ``typing.Sized`` | | | |
+----------------------------------+---------------+-------------------+----------------+ +----------------------------------+---------------+-------------------+----------------+
| ``typing.TypeAlias`` | 3.12 | Undecided | :pep:`695` |
+----------------------------------+---------------+-------------------+----------------+

View File

@ -1206,7 +1206,7 @@ A function definition defines a user-defined function object (see section
:ref:`types`): :ref:`types`):
.. productionlist:: python-grammar .. productionlist:: python-grammar
funcdef: [`decorators`] "def" `funcname` "(" [`parameter_list`] ")" funcdef: [`decorators`] "def" `funcname` [`type_params`] "(" [`parameter_list`] ")"
: ["->" `expression`] ":" `suite` : ["->" `expression`] ":" `suite`
decorators: `decorator`+ decorators: `decorator`+
decorator: "@" `assignment_expression` NEWLINE decorator: "@" `assignment_expression` NEWLINE
@ -1256,6 +1256,15 @@ except that the original function is not temporarily bound to the name ``func``.
:token:`~python-grammar:assignment_expression`. Previously, the grammar was :token:`~python-grammar:assignment_expression`. Previously, the grammar was
much more restrictive; see :pep:`614` for details. much more restrictive; see :pep:`614` for details.
A list of :ref:`type parameters <type-params>` may be given in square brackets
between the function's name and the opening parenthesis for its parameter list.
This indicates to static type checkers that the function is generic. At runtime,
the type parameters can be retrieved from the function's ``__type_params__``
attribute. See :ref:`generic-functions` for more.
.. versionchanged:: 3.12
Type parameter lists are new in Python 3.12.
.. index:: .. index::
triple: default; parameter; value triple: default; parameter; value
single: argument; function definition single: argument; function definition
@ -1378,7 +1387,7 @@ Class definitions
A class definition defines a class object (see section :ref:`types`): A class definition defines a class object (see section :ref:`types`):
.. productionlist:: python-grammar .. productionlist:: python-grammar
classdef: [`decorators`] "class" `classname` [`inheritance`] ":" `suite` classdef: [`decorators`] "class" `classname` [`type_params`] [`inheritance`] ":" `suite`
inheritance: "(" [`argument_list`] ")" inheritance: "(" [`argument_list`] ")"
classname: `identifier` classname: `identifier`
@ -1434,6 +1443,15 @@ decorators. The result is then bound to the class name.
:token:`~python-grammar:assignment_expression`. Previously, the grammar was :token:`~python-grammar:assignment_expression`. Previously, the grammar was
much more restrictive; see :pep:`614` for details. much more restrictive; see :pep:`614` for details.
A list of :ref:`type parameters <type-params>` may be given in square brackets
immediately after the class's name.
This indicates to static type checkers that the class is generic. At runtime,
the type parameters can be retrieved from the class's ``__type_params__``
attribute. See :ref:`generic-classes` for more.
.. versionchanged:: 3.12
Type parameter lists are new in Python 3.12.
**Programmer's note:** Variables defined in the class definition are class **Programmer's note:** Variables defined in the class definition are class
attributes; they are shared by instances. Instance attributes can be set in a attributes; they are shared by instances. Instance attributes can be set in a
method with ``self.name = value``. Both class and instance attributes are method with ``self.name = value``. Both class and instance attributes are
@ -1589,6 +1607,228 @@ body of a coroutine function.
The proposal that made coroutines a proper standalone concept in Python, The proposal that made coroutines a proper standalone concept in Python,
and added supporting syntax. and added supporting syntax.
.. _type-params:
Type parameter lists
====================
.. versionadded:: 3.12
.. index::
single: type parameters
.. productionlist:: python-grammar
type_params: "[" `type_param` ("," `type_param`)* "]"
type_param: `typevar` | `typevartuple` | `paramspec`
typevar: `identifier` (":" `expression`)?
typevartuple: "*" `identifier`
paramspec: "**" `identifier`
:ref:`Functions <def>` (including :ref:`coroutines <async def>`),
:ref:`classes <class>` and :ref:`type aliases <type>` may
contain a type parameter list::
def max[T](args: list[T]) -> T:
...
async def amax[T](args: list[T]) -> T:
...
class Bag[T]:
def __iter__(self) -> Iterator[T]:
...
def add(self, arg: T) -> None:
...
type ListOrSet[T] = list[T] | set[T]
Semantically, this indicates that the function, class, or type alias is
generic over a type variable. This information is primarily used by static
type checkers, and at runtime, generic objects behave much like their
non-generic counterparts.
Type parameters are declared in square brackets (``[]``) immediately
after the name of the function, class, or type alias. The type parameters
are accessible within the scope of the generic object, but not elsewhere.
Thus, after a declaration ``def func[T](): pass``, the name ``T`` is not available in
the module scope. Below, the semantics of generic objects are described
with more precision. The scope of type parameters is modeled with a special
function (technically, an :ref:`annotation scope <annotation-scopes>`) that
wraps the creation of the generic object.
Generic functions, classes, and type aliases have a :attr:`!__type_params__`
attribute listing their type parameters.
Type parameters come in three kinds:
* :data:`typing.TypeVar`, introduced by a plain name (e.g., ``T``). Semantically, this
represents a single type to a type checker.
* :data:`typing.TypeVarTuple`, introduced by a name prefixed with a single
asterisk (e.g., ``*Ts``). Semantically, this stands for a tuple of any
number of types.
* :data:`typing.ParamSpec`, introduced by a name prefixed with two asterisks
(e.g., ``**P``). Semantically, this stands for the parameters of a callable.
:data:`typing.TypeVar` declarations can define *bounds* and *constraints* with
a colon (``:``) followed by an expression. A single expression after the colon
indicates a bound (e.g. ``T: int``). Semantically, this means
that the :data:`!typing.TypeVar` can only represent types that are a subtype of
this bound. A parenthesized tuple of expressions after the colon indicates a
set of constraints (e.g. ``T: (str, bytes)``). Each member of the tuple should be a
type (again, this is not enforced at runtime). Constrained type variables can only
take on one of the types in the list of constraints.
For :data:`!typing.TypeVar`\ s declared using the type parameter list syntax,
the bound and constraints are not evaluated when the generic object is created,
but only when the value is explicitly accessed through the attributes ``__bound__``
and ``__constraints__``. To accomplish this, the bounds or constraints are
evaluated in a separate :ref:`annotation scope <annotation-scopes>`.
:data:`typing.TypeVarTuple`\ s and :data:`typing.ParamSpec`\ s cannot have bounds
or constraints.
The following example indicates the full set of allowed type parameter declarations::
def overly_generic[
SimpleTypeVar,
TypeVarWithBound: int,
TypeVarWithConstraints: (str, bytes),
*SimpleTypeVarTuple,
**SimpleParamSpec,
](
a: SimpleTypeVar,
b: TypeVarWithBound,
c: Callable[SimpleParamSpec, TypeVarWithConstraints],
*d: SimpleTypeVarTuple,
): ...
.. _generic-functions:
Generic functions
-----------------
Generic functions are declared as follows::
def func[T](arg: T): ...
This syntax is equivalent to::
annotation-def TYPE_PARAMS_OF_func():
T = typing.TypeVar("T")
def func(arg: T): ...
func.__type_params__ = (T,)
return func
func = TYPE_PARAMS_OF_func()
Here ``annotation-def`` indicates an :ref:`annotation scope <annotation-scopes>`,
which is not actually bound to any name at runtime. (One
other liberty is taken in the translation: the syntax does not go through
attribute access on the :mod:`typing` module, but creates an instance of
:data:`typing.TypeVar` directly.)
The annotations of generic functions are evaluated within the annotation scope
used for declaring the type parameters, but the function's defaults and
decorators are not.
The following example illustrates the scoping rules for these cases,
as well as for additional flavors of type parameters::
@decorator
def func[T: int, *Ts, **P](*args: *Ts, arg: Callable[P, T] = some_default):
...
Except for the :ref:`lazy evaluation <lazy-evaluation>` of the
:class:`~typing.TypeVar` bound, this is equivalent to::
DEFAULT_OF_arg = some_default
annotation-def TYPE_PARAMS_OF_func():
annotation-def BOUND_OF_T():
return int
# In reality, BOUND_OF_T() is evaluated only on demand.
T = typing.TypeVar("T", bound=BOUND_OF_T())
Ts = typing.TypeVarTuple("Ts")
P = typing.ParamSpec("P")
def func(*args: *Ts, arg: Callable[P, T] = DEFAULT_OF_arg):
...
func.__type_params__ = (T, Ts, P)
return func
func = decorator(TYPE_PARAMS_OF_func())
The capitalized names like ``DEFAULT_OF_arg`` are not actually
bound at runtime.
.. _generic-classes:
Generic classes
---------------
Generic classes are declared as follows::
class Bag[T]: ...
This syntax is equivalent to::
annotation-def TYPE_PARAMS_OF_Bag():
T = typing.TypeVar("T")
class Bag(typing.Generic[T]):
__type_params__ = (T,)
...
return Bag
Bag = TYPE_PARAMS_OF_Bag()
Here again ``annotation-def`` (not a real keyword) indicates an
:ref:`annotation scope <annotation-scopes>`, and the name
``TYPE_PARAMS_OF_Bag`` is not actually bound at runtime.
Generic classes implicitly inherit from :data:`typing.Generic`.
The base classes and keyword arguments of generic classes are
evaluated within the type scope for the type parameters,
and decorators are evaluated outside that scope. This is illustrated
by this example::
@decorator
class Bag(Base[T], arg=T): ...
This is equivalent to::
annotation-def TYPE_PARAMS_OF_Bag():
T = typing.TypeVar("T")
class Bag(Base[T], typing.Generic[T], arg=T):
__type_params__ = (T,)
...
return Bag
Bag = decorator(TYPE_PARAMS_OF_Bag())
.. _generic-type-aliases:
Generic type aliases
--------------------
The :keyword:`type` statement can also be used to create a generic type alias::
type ListOrSet[T] = list[T] | set[T]
Except for the :ref:`lazy evaluation <lazy-evaluation>` of the value,
this is equivalent to::
annotation-def TYPE_PARAMS_OF_ListOrSet():
T = typing.TypeVar("T")
annotation-def VALUE_OF_ListOrSet():
return list[T] | set[T]
# In reality, the value is lazily evaluated
return typing.TypeAliasType("ListOrSet", VALUE_OF_ListOrSet(), type_params=(T,))
ListOrSet = TYPE_PARAMS_OF_ListOrSet()
Here, ``annotation-def`` (not a real keyword) indicates an
:ref:`annotation scope <annotation-scopes>`. The capitalized names
like ``TYPE_PARAMS_OF_ListOrSet`` are not actually bound at runtime.
.. rubric:: Footnotes .. rubric:: Footnotes

View File

@ -499,6 +499,7 @@ Callable types
single: __globals__ (function attribute) single: __globals__ (function attribute)
single: __annotations__ (function attribute) single: __annotations__ (function attribute)
single: __kwdefaults__ (function attribute) single: __kwdefaults__ (function attribute)
single: __type_params__ (function attribute)
pair: global; namespace pair: global; namespace
+-------------------------+-------------------------------+-----------+ +-------------------------+-------------------------------+-----------+
@ -561,6 +562,12 @@ Callable types
| :attr:`__kwdefaults__` | A dict containing defaults | Writable | | :attr:`__kwdefaults__` | A dict containing defaults | Writable |
| | for keyword-only parameters. | | | | for keyword-only parameters. | |
+-------------------------+-------------------------------+-----------+ +-------------------------+-------------------------------+-----------+
| :attr:`__type_params__` | A tuple containing the | Writable |
| | :ref:`type parameters | |
| | <type-params>` of a | |
| | :ref:`generic function | |
| | <generic-functions>`. | |
+-------------------------+-------------------------------+-----------+
Most of the attributes labelled "Writable" check the type of the assigned value. Most of the attributes labelled "Writable" check the type of the assigned value.
@ -837,6 +844,7 @@ Custom classes
single: __bases__ (class attribute) single: __bases__ (class attribute)
single: __doc__ (class attribute) single: __doc__ (class attribute)
single: __annotations__ (class attribute) single: __annotations__ (class attribute)
single: __type_params__ (class attribute)
Special attributes: Special attributes:
@ -863,6 +871,10 @@ Custom classes
working with :attr:`__annotations__`, please see working with :attr:`__annotations__`, please see
:ref:`annotations-howto`. :ref:`annotations-howto`.
:attr:`__type_params__`
A tuple containing the :ref:`type parameters <type-params>` of
a :ref:`generic class <generic-classes>`.
Class instances Class instances
.. index:: .. index::
pair: object; class instance pair: object; class instance

View File

@ -71,6 +71,8 @@ The following constructs bind names:
+ in a capture pattern in structural pattern matching + in a capture pattern in structural pattern matching
* :keyword:`import` statements. * :keyword:`import` statements.
* :keyword:`type` statements.
* :ref:`type parameter lists <type-params>`.
The :keyword:`!import` statement of the form ``from ... import *`` binds all The :keyword:`!import` statement of the form ``from ... import *`` binds all
names defined in the imported module, except those beginning with an underscore. names defined in the imported module, except those beginning with an underscore.
@ -149,7 +151,8 @@ a global statement, the free variable is treated as a global.
The :keyword:`nonlocal` statement causes corresponding names to refer The :keyword:`nonlocal` statement causes corresponding names to refer
to previously bound variables in the nearest enclosing function scope. to previously bound variables in the nearest enclosing function scope.
:exc:`SyntaxError` is raised at compile time if the given name does not :exc:`SyntaxError` is raised at compile time if the given name does not
exist in any enclosing function scope. exist in any enclosing function scope. :ref:`Type parameters <type-params>`
cannot be rebound with the :keyword:`!nonlocal` statement.
.. index:: pair: module; __main__ .. index:: pair: module; __main__
@ -163,14 +166,119 @@ These references follow the normal rules for name resolution with an exception
that unbound local variables are looked up in the global namespace. that unbound local variables are looked up in the global namespace.
The namespace of the class definition becomes the attribute dictionary of The namespace of the class definition becomes the attribute dictionary of
the class. The scope of names defined in a class block is limited to the the class. The scope of names defined in a class block is limited to the
class block; it does not extend to the code blocks of methods -- this includes class block; it does not extend to the code blocks of methods. This includes
comprehensions and generator expressions since they are implemented using a comprehensions and generator expressions, but it does not include
function scope. This means that the following will fail:: :ref:`annotation scopes <annotation-scopes>`,
which have access to their enclosing class scopes.
This means that the following will fail::
class A: class A:
a = 42 a = 42
b = list(a + i for i in range(10)) b = list(a + i for i in range(10))
However, the following will succeed::
class A:
type Alias = Nested
class Nested: pass
print(A.Alias.__value__) # <type 'A.Nested'>
.. _annotation-scopes:
Annotation scopes
-----------------
:ref:`Type parameter lists <type-params>` and :keyword:`type` statements
introduce *annotation scopes*, which behave mostly like function scopes,
but with some exceptions discussed below. :term:`Annotations <annotation>`
currently do not use annotation scopes, but they are expected to use
annotation scopes in Python 3.13 when :pep:`649` is implemented.
Annotation scopes are used in the following contexts:
* Type parameter lists for :ref:`generic type aliases <generic-type-aliases>`.
* Type parameter lists for :ref:`generic functions <generic-functions>`.
A generic function's annotations are
executed within the annotation scope, but its defaults and decorators are not.
* Type parameter lists for :ref:`generic classes <generic-classes>`.
A generic class's base classes and
keyword arguments are executed within the annotation scope, but its decorators are not.
* The bounds and constraints for type variables
(:ref:`lazily evaluated <lazy-evaluation>`).
* The value of type aliases (:ref:`lazily evaluated <lazy-evaluation>`).
Annotation scopes differ from function scopes in the following ways:
* Annotation scopes have access to their enclosing class namespace.
If an annotation scope is immediately within a class scope, or within another
annotation scope that is immediately within a class scope, the code in the
annotation scope can use names defined in the class scope as if it were
executed directly within the class body. This contrasts with regular
functions defined within classes, which cannot access names defined in the class scope.
* Expressions in annotation scopes cannot contain :keyword:`yield`, ``yield from``,
:keyword:`await`, or :token:`:= <python-grammar:assignment_expression>`
expressions. (These expressions are allowed in other scopes contained within the
annotation scope.)
* Names defined in annotation scopes cannot be rebound with :keyword:`nonlocal`
statements in inner scopes. This includes only type parameters, as no other
syntactic elements that can appear within annotation scopes can introduce new names.
* While annotation scopes have an internal name, that name is not reflected in the
:term:`__qualname__ <qualified name>` of objects defined within the scope.
Instead, the :attr:`!__qualname__`
of such objects is as if the object were defined in the enclosing scope.
.. versionadded:: 3.12
Annotation scopes were introduced in Python 3.12 as part of :pep:`695`.
.. _lazy-evaluation:
Lazy evaluation
---------------
The values of type aliases created through the :keyword:`type` statement are
*lazily evaluated*. The same applies to the bounds and constraints of type
variables created through the :ref:`type parameter syntax <type-params>`.
This means that they are not evaluated when the type alias or type variable is
created. Instead, they are only evaluated when doing so is necessary to resolve
an attribute access.
Example:
.. doctest::
>>> type Alias = 1/0
>>> Alias.__value__
Traceback (most recent call last):
...
ZeroDivisionError: division by zero
>>> def func[T: 1/0](): pass
>>> T = func.__type_params__[0]
>>> T.__bound__
Traceback (most recent call last):
...
ZeroDivisionError: division by zero
Here the exception is raised only when the ``__value__`` attribute
of the type alias or the ``__bound__`` attribute of the type variable
is accessed.
This behavior is primarily useful for references to types that have not
yet been defined when the type alias or type variable is created. For example,
lazy evaluation enables creation of mutually recursive type aliases::
from typing import Literal
type SimpleExpr = int | Parenthesized
type Parenthesized = tuple[Literal["("], Expr, Literal[")"]]
type Expr = SimpleExpr | tuple[SimpleExpr, Literal["+", "-"], Expr]
Lazily evaluated values are evaluated in :ref:`annotation scope <annotation-scopes>`,
which means that names that appear inside the lazily evaluated value are looked up
as if they were used in the immediately enclosing scope.
.. versionadded:: 3.12
.. _restrict_exec: .. _restrict_exec:
Builtins and restricted execution Builtins and restricted execution

View File

@ -361,15 +361,19 @@ Soft Keywords
.. versionadded:: 3.10 .. versionadded:: 3.10
Some identifiers are only reserved under specific contexts. These are known as Some identifiers are only reserved under specific contexts. These are known as
*soft keywords*. The identifiers ``match``, ``case`` and ``_`` can *soft keywords*. The identifiers ``match``, ``case``, ``type`` and ``_`` can
syntactically act as keywords in contexts related to the pattern matching syntactically act as keywords in certain contexts,
statement, but this distinction is done at the parser level, not when but this distinction is done at the parser level, not when tokenizing.
tokenizing.
As soft keywords, their use with pattern matching is possible while still As soft keywords, their use in the grammar is possible while still
preserving compatibility with existing code that uses ``match``, ``case`` and ``_`` as preserving compatibility with existing code that uses these names as
identifier names. identifier names.
``match``, ``case``, and ``_`` are used in the :keyword:`match` statement.
``type`` is used in the :keyword:`type` statement.
.. versionchanged:: 3.12
``type`` is now a soft keyword.
.. index:: .. index::
single: _, identifiers single: _, identifiers

View File

@ -28,6 +28,7 @@ simple statements is:
: | `future_stmt` : | `future_stmt`
: | `global_stmt` : | `global_stmt`
: | `nonlocal_stmt` : | `nonlocal_stmt`
: | `type_stmt`
.. _exprstmts: .. _exprstmts:
@ -1012,3 +1013,48 @@ pre-existing bindings in the local scope.
:pep:`3104` - Access to Names in Outer Scopes :pep:`3104` - Access to Names in Outer Scopes
The specification for the :keyword:`nonlocal` statement. The specification for the :keyword:`nonlocal` statement.
.. _type:
The :keyword:`!type` statement
==============================
.. index:: pair: statement; type
.. productionlist:: python-grammar
type_stmt: 'type' `identifier` [`type_params`] "=" `expression`
The :keyword:`!type` statement declares a type alias, which is an instance
of :class:`typing.TypeAliasType`.
For example, the following statement creates a type alias::
type Point = tuple[float, float]
This code is roughly equivalent to::
annotation-def VALUE_OF_Point():
return tuple[float, float]
Point = typing.TypeAliasType("Point", VALUE_OF_Point())
``annotation-def`` indicates an :ref:`annotation scope <annotation-scopes>`, which behaves
mostly like a function, but with several small differences.
The value of the
type alias is evaluated in the annotation scope. It is not evaluated when the
type alias is created, but only when the value is accessed through the type alias's
:attr:`!__value__` attribute (see :ref:`lazy-evaluation`).
This allows the type alias to refer to names that are not yet defined.
Type aliases may be made generic by adding a :ref:`type parameter list <type-params>`
after the name. See :ref:`generic-type-aliases` for more.
:keyword:`!type` is a :ref:`soft keyword <soft-keywords>`.
.. versionadded:: 3.12
.. seealso::
:pep:`695` - Type Parameter Syntax
Introduced the :keyword:`!type` statement and syntax for
generic classes and functions.

View File

@ -74,6 +74,8 @@ New typing features:
* :pep:`688`: Making the buffer protocol accessible in Python * :pep:`688`: Making the buffer protocol accessible in Python
* :ref:`whatsnew312-pep695`
* :ref:`whatsnew312-pep692` * :ref:`whatsnew312-pep692`
* :pep:`698`: Override Decorator for Static Typing * :pep:`698`: Override Decorator for Static Typing
@ -272,6 +274,70 @@ See :pep:`692` for more details.
(PEP written by Franek Magiera) (PEP written by Franek Magiera)
.. _whatsnew312-pep695:
PEP 695: Type Parameter Syntax
------------------------------
Generic classes and functions under :pep:`484` were declared using a verbose syntax
that left the scope of type parameters unclear and required explicit declarations of
variance.
:pep:`695` introduces a new, more compact and explicit way to create
:ref:`generic classes <generic-classes>` and :ref:`functions <generic-functions>`::
def max[T](args: Iterable[T]) -> T:
...
class list[T]:
def __getitem__(self, index: int, /) -> T:
...
def append(self, element: T) -> None:
...
In addition, the PEP introduces a new way to declare :ref:`type aliases <type-aliases>`
using the :keyword:`type` statement, which creates an instance of
:class:`~typing.TypeAliasType`::
type Point = tuple[float, float]
Type aliases can also be :ref:`generic <generic-type-aliases>`::
type Point[T] = tuple[T, T]
The new syntax allows declaring :class:`~typing.TypeVarTuple`
and :class:`~typing.ParamSpec` parameters, as well as :class:`~typing.TypeVar`
parameters with bounds or constraints::
type IntFunc[**P] = Callable[P, int] # ParamSpec
type LabeledTuple[*Ts] = tuple[str, *Ts] # TypeVarTuple
type HashableSequence[T: Hashable] = Sequence[T] # TypeVar with bound
type IntOrStrSequence[T: (int, str)] = Sequence[T] # TypeVar with constraints
The value of type aliases and the bound and constraints of type variables
created through this syntax are evaluated only on demand (see
:ref:`lazy-evaluation`). This means type aliases are able to refer to other
types defined later in the file.
Type parameters declared through a type parameter list are visible within the
scope of the declaration and any nested scopes, but not in the outer scope. For
example, they can be used in the type annotations for the methods of a generic
class or in the class body. However, they cannot be used in the module scope after
the class is defined. See :ref:`type-params` for a detailed description of the
runtime semantics of type parameters.
In order to support these scoping semantics, a new kind of scope is introduced,
the :ref:`annotation scope <annotation-scopes>`. Annotation scopes behave for the
most part like function scopes, but interact differently with enclosing class scopes.
In Python 3.13, :term:`annotations <annotation>` will also be evaluated in
annotation scopes.
See :pep:`695` for more details.
(PEP written by Eric Traut. Implementation by Jelle Zijlstra, Eric Traut,
and others in :gh:`103764`.)
Other Language Changes Other Language Changes
====================== ======================
@ -806,14 +872,19 @@ Optimizations
CPython bytecode changes CPython bytecode changes
======================== ========================
* Removed the :opcode:`LOAD_METHOD` instruction. It has been merged into * Remove the :opcode:`LOAD_METHOD` instruction. It has been merged into
:opcode:`LOAD_ATTR`. :opcode:`LOAD_ATTR` will now behave like the old :opcode:`LOAD_ATTR`. :opcode:`LOAD_ATTR` will now behave like the old
:opcode:`LOAD_METHOD` instruction if the low bit of its oparg is set. :opcode:`LOAD_METHOD` instruction if the low bit of its oparg is set.
(Contributed by Ken Jin in :gh:`93429`.) (Contributed by Ken Jin in :gh:`93429`.)
* Removed the :opcode:`!JUMP_IF_FALSE_OR_POP` and :opcode:`!JUMP_IF_TRUE_OR_POP` * Remove the :opcode:`!JUMP_IF_FALSE_OR_POP` and :opcode:`!JUMP_IF_TRUE_OR_POP`
instructions. (Contributed by Irit Katriel in :gh:`102859`.) instructions. (Contributed by Irit Katriel in :gh:`102859`.)
* Add the :opcode:`LOAD_FROM_DICT_OR_DEREF`, :opcode:`LOAD_FROM_DICT_OR_GLOBALS`,
and :opcode:`LOAD_LOCALS` opcodes as part of the implementation of :pep:`695`.
Remove the :opcode:`!LOAD_CLASSDEREF` opcode, which can be replaced with
:opcode:`LOAD_LOCALS` plus :opcode:`LOAD_FROM_DICT_OR_DEREF`. (Contributed
by Jelle Zijlstra in :gh:`103764`.)
Demos and Tools Demos and Tools
=============== ===============

View File

@ -443,45 +443,38 @@ static PyMethodDef typevar_methods[] = {
PyDoc_STRVAR(typevar_doc, PyDoc_STRVAR(typevar_doc,
"Type variable.\n\ "Type variable.\n\
\n\ \n\
Usage::\n\ The preferred way to construct a type variable is via the dedicated syntax\n\
for generic functions, classes, and type aliases:\n\
\n\
class Sequence[T]: # T is a TypeVar\n\
...\n\
\n\
This syntax can also be used to create bound and constrained type\n\
variables:\n\
\n\
class StrSequence[S: str]: # S is a TypeVar bound to str\n\
...\n\
\n\
class StrOrBytesSequence[A: (str, bytes)]: # A is a TypeVar constrained to str or bytes\n\
...\n\
\n\
However, if desired, reusable type variables can also be constructed\n\
manually, like so:\n\
\n\ \n\
T = TypeVar('T') # Can be anything\n\ T = TypeVar('T') # Can be anything\n\
A = TypeVar('A', str, bytes) # Must be str or bytes\n\ S = TypeVar('S', bound=str) # Can be any subtype of str\n\
A = TypeVar('A', str, bytes) # Must be exactly str or bytes\n\
\n\ \n\
Type variables exist primarily for the benefit of static type\n\ Type variables exist primarily for the benefit of static type\n\
checkers. They serve as the parameters for generic types as well\n\ checkers. They serve as the parameters for generic types as well\n\
as for generic function definitions. See class Generic for more\n\ as for generic function and type alias definitions.\n\
information on generic types. Generic functions work as follows:\n\
\n\ \n\
def repeat(x: T, n: int) -> List[T]:\n\ The variance of type variables is inferred by type checkers when they are created\n\
'''Return a list containing n references to x.'''\n\ through the type parameter syntax and when ``infer_variance=True`` is passed.\n\
return [x]*n\n\ Manually created type variables may be explicitly marked covariant or\n\
\n\ contravariant by passing ``covariant=True`` or ``contravariant=True``.\n\
def longest(x: A, y: A) -> A:\n\ By default, manually created type variables are invariant. See PEP 484\n\
'''Return the longest of two strings.'''\n\ and PEP 695 for more details.\n\
return x if len(x) >= len(y) else y\n\
\n\
The latter example's signature is essentially the overloading\n\
of (str, str) -> str and (bytes, bytes) -> bytes. Also note\n\
that if the arguments are instances of some subclass of str,\n\
the return type is still plain str.\n\
\n\
At runtime, isinstance(x, T) and issubclass(C, T) will raise TypeError.\n\
\n\
Type variables defined with covariant=True or contravariant=True\n\
can be used to declare covariant or contravariant generic types.\n\
See PEP 484 for more details. By default generic types are invariant\n\
in all type variables.\n\
\n\
Type variables can be introspected. e.g.:\n\
\n\
T.__name__ == 'T'\n\
T.__constraints__ == ()\n\
T.__covariant__ == False\n\
T.__contravariant__ = False\n\
A.__constraints__ == (str, bytes)\n\
\n\
Note that only type variables defined in global scope can be pickled.\n\
"); ");
static PyType_Slot typevar_slots[] = { static PyType_Slot typevar_slots[] = {
@ -942,7 +935,14 @@ static PyMethodDef paramspec_methods[] = {
PyDoc_STRVAR(paramspec_doc, PyDoc_STRVAR(paramspec_doc,
"Parameter specification variable.\n\ "Parameter specification variable.\n\
\n\ \n\
Usage::\n\ The preferred way to construct a parameter specification is via the dedicated syntax\n\
for generic functions, classes, and type aliases, where\n\
the use of '**' creates a parameter specification:\n\
\n\
type IntFunc[**P] = Callable[P, int]\n\
\n\
For compatibility with Python 3.11 and earlier, ParamSpec objects\n\
can also be created as follows:\n\
\n\ \n\
P = ParamSpec('P')\n\ P = ParamSpec('P')\n\
\n\ \n\
@ -952,12 +952,9 @@ callable to another callable, a pattern commonly found in higher order\n\
functions and decorators. They are only valid when used in ``Concatenate``,\n\ functions and decorators. They are only valid when used in ``Concatenate``,\n\
or as the first argument to ``Callable``, or as parameters for user-defined\n\ or as the first argument to ``Callable``, or as parameters for user-defined\n\
Generics. See class Generic for more information on generic types. An\n\ Generics. See class Generic for more information on generic types. An\n\
example for annotating a decorator::\n\ example for annotating a decorator:\n\
\n\ \n\
T = TypeVar('T')\n\ def add_logging[**P, T](f: Callable[P, T]) -> Callable[P, T]:\n\
P = ParamSpec('P')\n\
\n\
def add_logging(f: Callable[P, T]) -> Callable[P, T]:\n\
'''A type-safe decorator to add logging to a function.'''\n\ '''A type-safe decorator to add logging to a function.'''\n\
def inner(*args: P.args, **kwargs: P.kwargs) -> T:\n\ def inner(*args: P.args, **kwargs: P.kwargs) -> T:\n\
logging.info(f'{f.__name__} was called')\n\ logging.info(f'{f.__name__} was called')\n\
@ -969,17 +966,9 @@ example for annotating a decorator::\n\
'''Add two numbers together.'''\n\ '''Add two numbers together.'''\n\
return x + y\n\ return x + y\n\
\n\ \n\
Parameter specification variables defined with covariant=True or\n\
contravariant=True can be used to declare covariant or contravariant\n\
generic types. These keyword arguments are valid, but their actual semantics\n\
are yet to be decided. See PEP 612 for details.\n\
\n\
Parameter specification variables can be introspected. e.g.:\n\ Parameter specification variables can be introspected. e.g.:\n\
\n\ \n\
P.__name__ == 'P'\n\ P.__name__ == 'P'\n\
P.__bound__ == None\n\
P.__covariant__ == False\n\
P.__contravariant__ == False\n\
\n\ \n\
Note that only parameter specification variables defined in global scope can\n\ Note that only parameter specification variables defined in global scope can\n\
be pickled.\n\ be pickled.\n\
@ -1175,9 +1164,18 @@ static PyMethodDef typevartuple_methods[] = {
}; };
PyDoc_STRVAR(typevartuple_doc, PyDoc_STRVAR(typevartuple_doc,
"Type variable tuple.\n\ "Type variable tuple. A specialized form of type variable that enables\n\
variadic generics.\n\
\n\ \n\
Usage:\n\ The preferred way to construct a type variable tuple is via the dedicated syntax\n\
for generic functions, classes, and type aliases, where a single\n\
'*' indicates a type variable tuple:\n\
\n\
def move_first_element_to_last[T, *Ts](tup: tuple[T, *Ts]) -> tuple[*Ts, T]:\n\
return (*tup[1:], tup[0])\n\
\n\
For compatibility with Python 3.11 and earlier, TypeVarTuple objects\n\
can also be created as follows:\n\
\n\ \n\
Ts = TypeVarTuple('Ts') # Can be given any name\n\ Ts = TypeVarTuple('Ts') # Can be given any name\n\
\n\ \n\
@ -1185,7 +1183,7 @@ Just as a TypeVar (type variable) is a placeholder for a single type,\n\
a TypeVarTuple is a placeholder for an *arbitrary* number of types. For\n\ a TypeVarTuple is a placeholder for an *arbitrary* number of types. For\n\
example, if we define a generic class using a TypeVarTuple:\n\ example, if we define a generic class using a TypeVarTuple:\n\
\n\ \n\
class C(Generic[*Ts]): ...\n\ class C[*Ts]: ...\n\
\n\ \n\
Then we can parameterize that class with an arbitrary number of type\n\ Then we can parameterize that class with an arbitrary number of type\n\
arguments:\n\ arguments:\n\
@ -1441,6 +1439,23 @@ PyDoc_STRVAR(typealias_doc,
Type aliases are created through the type statement:\n\ Type aliases are created through the type statement:\n\
\n\ \n\
type Alias = int\n\ type Alias = int\n\
\n\
In this example, Alias and int will be treated equivalently by static\n\
type checkers.\n\
\n\
At runtime, Alias is an instance of TypeAliasType. The __name__ attribute\n\
holds the name of the type alias. The value of the type\n\
alias is stored in the __value__ attribute. It is evaluated lazily, so\n\
the value is computed only if the attribute is accessed.\n\
\n\
Type aliases can also be generic:\n\
\n\
type ListOrSet[T] = list[T] | set[T]\n\
\n\
In this case, the type parameters of the alias are stored in the\n\
__type_params__ attribute.\n\
\n\
See PEP 695 for more information.\n\
"); ");
static PyNumberMethods typealias_as_number = { static PyNumberMethods typealias_as_number = {
@ -1489,14 +1504,14 @@ PyDoc_STRVAR(generic_doc,
\n\ \n\
A generic type is typically declared by inheriting from\n\ A generic type is typically declared by inheriting from\n\
this class parameterized with one or more type variables.\n\ this class parameterized with one or more type variables.\n\
For example, a generic mapping type might be defined as::\n\ For example, a generic mapping type might be defined as:\n\
\n\ \n\
class Mapping(Generic[KT, VT]):\n\ class Mapping(Generic[KT, VT]):\n\
def __getitem__(self, key: KT) -> VT:\n\ def __getitem__(self, key: KT) -> VT:\n\
...\n\ ...\n\
# Etc.\n\ # Etc.\n\
\n\ \n\
This class can then be used as follows::\n\ This class can then be used as follows:\n\
\n\ \n\
def lookup_name(mapping: Mapping[KT, VT], key: KT, default: VT) -> VT:\n\ def lookup_name(mapping: Mapping[KT, VT], key: KT, default: VT) -> VT:\n\
try:\n\ try:\n\