mirror of https://github.com/python/cpython
gh-103921: Document PEP 695 (#104642)
Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
This commit is contained in:
parent
95f1b1fef7
commit
060277d96b
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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` |
|
||||||
|
+----------------------------------+---------------+-------------------+----------------+
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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
|
||||||
===============
|
===============
|
||||||
|
|
|
@ -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\
|
||||||
|
|
Loading…
Reference in New Issue