gh-119180: Documentation for PEP 649 and 749 (#122235)

Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com>
Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com>
Co-authored-by: Carol Willing <carolcode@willingconsulting.com>
This commit is contained in:
Jelle Zijlstra 2024-09-11 07:49:59 -07:00 committed by GitHub
parent 6e23c89fcd
commit 5436d8b9c3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 680 additions and 104 deletions

View File

@ -36,6 +36,12 @@ Glossary
and loaders (in the :mod:`importlib.abc` module). You can create your own and loaders (in the :mod:`importlib.abc` module). You can create your own
ABCs with the :mod:`abc` module. ABCs with the :mod:`abc` module.
annotate function
A function that can be called to retrieve the :term:`annotations <annotation>`
of an object. This function is accessible as the :attr:`~object.__annotate__`
attribute of functions, classes, and modules. Annotate functions are a
subset of :term:`evaluate functions <evaluate function>`.
annotation annotation
A label associated with a variable, a class A label associated with a variable, a class
attribute or a function parameter or return value, attribute or a function parameter or return value,
@ -43,12 +49,11 @@ Glossary
Annotations of local variables cannot be accessed at runtime, but Annotations of local variables cannot be accessed at runtime, but
annotations of global variables, class attributes, and functions annotations of global variables, class attributes, and functions
are stored in the :attr:`__annotations__` can be retrieved by calling :func:`annotationlib.get_annotations`
special attribute of modules, classes, and functions, on modules, classes, and functions, respectively.
respectively.
See :term:`variable annotation`, :term:`function annotation`, :pep:`484` See :term:`variable annotation`, :term:`function annotation`, :pep:`484`,
and :pep:`526`, which describe this functionality. :pep:`526`, and :pep:`649`, which describe this functionality.
Also see :ref:`annotations-howto` Also see :ref:`annotations-howto`
for best practices on working with annotations. for best practices on working with annotations.
@ -366,6 +371,11 @@ Glossary
statements. The technique contrasts with the :term:`LBYL` style statements. The technique contrasts with the :term:`LBYL` style
common to many other languages such as C. common to many other languages such as C.
evaluate function
A function that can be called to evaluate a lazily evaluated attribute
of an object, such as the value of type aliases created with the :keyword:`type`
statement.
expression expression
A piece of syntax which can be evaluated to some value. In other words, A piece of syntax which can be evaluated to some value. In other words,
an expression is an accumulation of expression elements like literals, an expression is an accumulation of expression elements like literals,

View File

@ -34,11 +34,16 @@ Accessing The Annotations Dict Of An Object In Python 3.10 And Newer
Python 3.10 adds a new function to the standard library: Python 3.10 adds a new function to the standard library:
:func:`inspect.get_annotations`. In Python versions 3.10 :func:`inspect.get_annotations`. In Python versions 3.10
and newer, calling this function is the best practice for through 3.13, calling this function is the best practice for
accessing the annotations dict of any object that supports accessing the annotations dict of any object that supports
annotations. This function can also "un-stringize" annotations. This function can also "un-stringize"
stringized annotations for you. stringized annotations for you.
In Python 3.14, there is a new :mod:`annotationlib` module
with functionality for working with annotations. This
includes a :func:`annotationlib.get_annotations` function,
which supersedes :func:`inspect.get_annotations`.
If for some reason :func:`inspect.get_annotations` isn't If for some reason :func:`inspect.get_annotations` isn't
viable for your use case, you may access the viable for your use case, you may access the
``__annotations__`` data member manually. Best practice ``__annotations__`` data member manually. Best practice
@ -184,7 +189,11 @@ Best Practices For ``__annotations__`` In Any Python Version
* If you do assign directly to the ``__annotations__`` member * If you do assign directly to the ``__annotations__`` member
of an object, you should always set it to a ``dict`` object. of an object, you should always set it to a ``dict`` object.
* If you directly access the ``__annotations__`` member * You should avoid accessing ``__annotations__`` directly on any object.
Instead, use :func:`annotationlib.get_annotations` (Python 3.14+)
or :func:`inspect.get_annotations` (Python 3.10+).
* If you do directly access the ``__annotations__`` member
of an object, you should ensure that it's a of an object, you should ensure that it's a
dictionary before attempting to examine its contents. dictionary before attempting to examine its contents.
@ -231,3 +240,11 @@ itself be quoted. In effect the annotation is quoted
This prints ``{'a': "'str'"}``. This shouldn't really be considered This prints ``{'a': "'str'"}``. This shouldn't really be considered
a "quirk"; it's mentioned here simply because it might be surprising. a "quirk"; it's mentioned here simply because it might be surprising.
If you use a class with a custom metaclass and access ``__annotations__``
on the class, you may observe unexpected behavior; see
:pep:`749 <749#pep749-metaclasses>` for some examples. You can avoid these
quirks by using :func:`annotationlib.get_annotations` on Python 3.14+ or
:func:`inspect.get_annotations` on Python 3.10+. On earlier versions of
Python, you can avoid these bugs by accessing the annotations from the
class's ``__dict__`` (e.g., ``cls.__dict__.get('__annotations__', None)``).

View File

@ -64,8 +64,10 @@ language using this mechanism:
| generator_stop | 3.5.0b1 | 3.7 | :pep:`479`: | | generator_stop | 3.5.0b1 | 3.7 | :pep:`479`: |
| | | | *StopIteration handling inside generators* | | | | | *StopIteration handling inside generators* |
+------------------+-------------+--------------+---------------------------------------------+ +------------------+-------------+--------------+---------------------------------------------+
| annotations | 3.7.0b1 | TBD [1]_ | :pep:`563`: | | annotations | 3.7.0b1 | Never [1]_ | :pep:`563`: |
| | | | *Postponed evaluation of annotations* | | | | | *Postponed evaluation of annotations*, |
| | | | :pep:`649`: *Deferred evalutation of |
| | | | annotations using descriptors* |
+------------------+-------------+--------------+---------------------------------------------+ +------------------+-------------+--------------+---------------------------------------------+
.. XXX Adding a new entry? Remember to update simple_stmts.rst, too. .. XXX Adding a new entry? Remember to update simple_stmts.rst, too.
@ -115,11 +117,9 @@ language using this mechanism:
.. [1] .. [1]
``from __future__ import annotations`` was previously scheduled to ``from __future__ import annotations`` was previously scheduled to
become mandatory in Python 3.10, but the Python Steering Council become mandatory in Python 3.10, but the change was delayed and ultimately
twice decided to delay the change canceled. This feature will eventually be deprecated and removed. See
(`announcement for Python 3.10 <https://mail.python.org/archives/list/python-dev@python.org/message/CLVXXPQ2T2LQ5MP2Y53VVQFCXYWQJHKZ/>`__; :pep:`649` and :pep:`749`.
`announcement for Python 3.11 <https://mail.python.org/archives/list/python-dev@python.org/message/VIZEBX5EYMSYIJNDBF6DMUMZOCWHARSO/>`__).
No final decision has been made yet. See also :pep:`563` and :pep:`649`.
.. seealso:: .. seealso::

View File

@ -0,0 +1,349 @@
:mod:`!annotationlib` --- Functionality for introspecting annotations
=====================================================================
.. module:: annotationlib
:synopsis: Functionality for introspecting annotations
**Source code:** :source:`Lib/annotationlib.py`
.. testsetup:: default
import annotationlib
from annotationlib import *
--------------
The :mod:`!annotationlib` module provides tools for introspecting
:term:`annotations <annotation>` on modules, classes, and functions.
Annotations are :ref:`lazily evaluated <lazy-evaluation>` and often contain
forward references to objects that are not yet defined when the annotation
is created. This module provides a set of low-level tools that can be used to retrieve annotations in a reliable way, even
in the presence of forward references and other edge cases.
This module supports retrieving annotations in three main formats
(see :class:`Format`), each of which works best for different use cases:
* :attr:`~Format.VALUE` evaluates the annotations and returns their value.
This is most straightforward to work with, but it may raise errors,
for example if the annotations contain references to undefined names.
* :attr:`~Format.FORWARDREF` returns :class:`ForwardRef` objects
for annotations that cannot be resolved, allowing you to inspect the
annotations without evaluating them. This is useful when you need to
work with annotations that may contain unresolved forward references.
* :attr:`~Format.SOURCE` returns the annotations as a string, similar
to how it would appear in the source file. This is useful for documentation
generators that want to display annotations in a readable way.
The :func:`get_annotations` function is the main entry point for
retrieving annotations. Given a function, class, or module, it returns
an annotations dictionary in the requested format. This module also provides
functionality for working directly with the :term:`annotate function`
that is used to evaluate annotations, such as :func:`get_annotate_function`
and :func:`call_annotate_function`, as well as the
:func:`call_evaluate_function` function for working with
:term:`evaluate functions <evaluate function>`.
.. seealso::
:pep:`649` proposed the current model for how annotations work in Python.
:pep:`749` expanded on various aspects of :pep:`649` and introduced the
:mod:`!annotationlib` module.
:ref:`annotations-howto` provides best practices for working with
annotations.
:pypi:`typing-extensions` provides a backport of :func:`get_annotations`
that works on earlier versions of Python.
Annotation semantics
--------------------
The way annotations are evaluated has changed over the history of Python 3,
and currently still depends on a :ref:`future import <future>`.
There have been execution models for annotations:
* *Stock semantics* (default in Python 3.0 through 3.13; see :pep:`3107`
and :pep:`526`): Annotations are evaluated eagerly, as they are
encountered in the source code.
* *Stringified annotations* (used with ``from __future__ import annotations``
in Python 3.7 and newer; see :pep:`563`): Annotations are stored as
strings only.
* *Deferred evaluation* (default in Python 3.14 and newer; see :pep:`649` and
:pep:`749`): Annotations are evaluated lazily, only when they are accessed.
As an example, consider the following program::
def func(a: Cls) -> None:
print(a)
class Cls: pass
print(func.__annotations__)
This will behave as follows:
* Under stock semantics (Python 3.13 and earlier), it will throw a
:exc:`NameError` at the line where ``func`` is defined,
because ``Cls`` is an undefined name at that point.
* Under stringified annotations (if ``from __future__ import annotations``
is used), it will print ``{'a': 'Cls', 'return': 'None'}``.
* Under deferred evaluation (Python 3.14 and later), it will print
``{'a': <class 'Cls'>, 'return': None}``.
Stock semantics were used when function annotations were first introduced
in Python 3.0 (by :pep:`3107`) because this was the simplest, most obvious
way to implement annotations. The same execution model was used when variable
annotations were introduced in Python 3.6 (by :pep:`526`). However,
stock semantics caused problems when using annotations as type hints,
such as a need to refer to names that are not yet defined when the
annotation is encountered. In addition, there were performance problems
with executing annotations at module import time. Therefore, in Python 3.7,
:pep:`563` introduced the ability to store annotations as strings using the
``from __future__ import annotations`` syntax. The plan at the time was to
eventually make this behavior the default, but a problem appeared:
stringified annotations are more difficult to process for those who
introspect annotations at runtime. An alternative proposal, :pep:`649`,
introduced the third execution model, deferred evaluation, and was implemented
in Python 3.14. Stringified annotations are still used if
``from __future__ import annotations`` is present, but this behavior will
eventually be removed.
Classes
-------
.. class:: Format
An :class:`~enum.IntEnum` describing the formats in which annotations
can be returned. Members of the enum, or their equivalent integer values,
can be passed to :func:`get_annotations` and other functions in this
module, as well as to :attr:`~object.__annotate__` functions.
.. attribute:: VALUE
:value: 1
Values are the result of evaluating the annotation expressions.
.. attribute:: FORWARDREF
:value: 2
Values are real annotation values (as per :attr:`Format.VALUE` format)
for defined values, and :class:`ForwardRef` proxies for undefined
values. Real objects may contain references to, :class:`ForwardRef`
proxy objects.
.. attribute:: SOURCE
:value: 3
Values are the text string of the annotation as it appears in the
source code, up to modifications including, but not restricted to,
whitespace normalizations and constant values optimizations.
The exact values of these strings may change in future versions of Python.
.. versionadded:: 3.14
.. class:: ForwardRef
A proxy object for forward references in annotations.
Instances of this class are returned when the :attr:`~Format.FORWARDREF`
format is used and annotations contain a name that cannot be resolved.
This can happen when a forward reference is used in an annotation, such as
when a class is referenced before it is defined.
.. attribute:: __forward_arg__
A string containing the code that was evaluated to produce the
:class:`~ForwardRef`. The string may not be exactly equivalent
to the original source.
.. method:: evaluate(*, globals=None, locals=None, type_params=None, owner=None)
Evaluate the forward reference, returning its value.
This may throw an exception, such as :exc:`NameError`, if the forward
reference refers to names that do not exist. The arguments to this
method can be used to provide bindings for names that would otherwise
be undefined.
:class:`~ForwardRef` instances returned by :func:`get_annotations`
retain references to information about the scope they originated from,
so calling this method with no further arguments may be sufficient to
evaluate such objects. :class:`~ForwardRef` instances created by other
means may not have any information about their scope, so passing
arguments to this method may be necessary to evaluate them successfully.
*globals* and *locals* are passed to :func:`eval`, representing
the global and local namespaces in which the name is evaluated.
*type_params*, if given, must be a tuple of
:ref:`type parameters <type-params>` that are in scope while the forward
reference is being evaluated. *owner* is the object that owns the
annotation from which the forward reference derives, usually a function,
class, or module.
.. important::
Once a :class:`~ForwardRef` instance has been evaluated, it caches
the evaluated value, and future calls to :meth:`evaluate` will return
the cached value, regardless of the parameters passed in.
.. versionadded:: 3.14
Functions
---------
.. function:: call_annotate_function(annotate, format, *, owner=None)
Call the :term:`annotate function` *annotate* with the given *format*,
a member of the :class:`Format` enum, and return the annotations
dictionary produced by the function.
This helper function is required because annotate functions generated by
the compiler for functions, classes, and modules only support
the :attr:`~Format.VALUE` format when called directly.
To support other formats, this function calls the annotate function
in a special environment that allows it to produce annotations in the
other formats. This is a useful building block when implementing
functionality that needs to partially evaluate annotations while a class
is being constructed.
*owner* is the object that owns the annotation function, usually
a function, class, or module. If provided, it is used in the
:attr:`~Format.FORWARDREF` format to produce a :class:`ForwardRef`
object that carries more information.
.. seealso::
:PEP:`PEP 649 <649#the-stringizer-and-the-fake-globals-environment>`
contains an explanation of the implementation technique used by this
function.
.. versionadded:: 3.14
.. function:: call_evaluate_function(evaluate, format, *, owner=None)
Call the :term:`evaluate function` *evaluate* with the given *format*,
a member of the :class:`Format` enum, and return the value produced by
the function. This is similar to :func:`call_annotate_function`,
but the latter always returns a dictionary mapping strings to annotations,
while this function returns a single value.
This is intended for use with the evaluate functions generated for lazily
evaluated elements related to type aliases and type parameters:
* :meth:`typing.TypeAliasType.evaluate_value`, the value of type aliases
* :meth:`typing.TypeVar.evaluate_bound`, the bound of type variables
* :meth:`typing.TypeVar.evaluate_constraints`, the constraints of
type variables
* :meth:`typing.TypeVar.evaluate_default`, the default value of
type variables
* :meth:`typing.ParamSpec.evaluate_default`, the default value of
parameter specifications
* :meth:`typing.TypeVarTuple.evaluate_default`, the default value of
type variable tuples
*owner* is the object that owns the evaluate function, such as the type
alias or type variable object.
*format* can be used to control the format in which the value is returned:
.. doctest::
>>> type Alias = undefined
>>> call_evaluate_function(Alias.evaluate_value, Format.VALUE)
Traceback (most recent call last):
...
NameError: name 'undefined' is not defined
>>> call_evaluate_function(Alias.evaluate_value, Format.FORWARDREF)
ForwardRef('undefined')
>>> call_evaluate_function(Alias.evaluate_value, Format.SOURCE)
'undefined'
.. versionadded:: 3.14
.. function:: get_annotate_function(obj)
Retrieve the :term:`annotate function` for *obj*. Return :const:`!None`
if *obj* does not have an annotate function.
This is usually equivalent to accessing the :attr:`~object.__annotate__`
attribute of *obj*, but direct access to the attribute may return the wrong
object in certain situations involving metaclasses. This function should be
used instead of accessing the attribute directly.
.. versionadded:: 3.14
.. function:: get_annotations(obj, *, globals=None, locals=None, eval_str=False, format=Format.VALUE)
Compute the annotations dict for an object.
*obj* may be a callable, class, module, or other object with
:attr:`~object.__annotate__` and :attr:`~object.__annotations__` attributes.
Passing in an object of any other type raises :exc:`TypeError`.
The *format* parameter controls the format in which annotations are returned,
and must be a member of the :class:`Format` enum or its integer equivalent.
Returns a dict. :func:`!get_annotations` returns a new dict every time
it's called; calling it twice on the same object will return two
different but equivalent dicts.
This function handles several details for you:
* If *eval_str* is true, values of type :class:`!str` will
be un-stringized using :func:`eval`. This is intended
for use with stringized annotations
(``from __future__ import annotations``). It is an error
to set *eval_str* to true with formats other than :attr:`Format.VALUE`.
* If *obj* doesn't have an annotations dict, returns an
empty dict. (Functions and methods always have an
annotations dict; classes, modules, and other types of
callables may not.)
* Ignores inherited annotations on classes, as well as annotations
on metaclasses. If a class
doesn't have its own annotations dict, returns an empty dict.
* All accesses to object members and dict values are done
using ``getattr()`` and ``dict.get()`` for safety.
*eval_str* controls whether or not values of type :class:`!str` are
replaced with the result of calling :func:`eval` on those values:
* If eval_str is true, :func:`eval` is called on values of type
:class:`!str`. (Note that :func:`!get_annotations` doesn't catch
exceptions; if :func:`eval()` raises an exception, it will unwind
the stack past the :func:`!get_annotations` call.)
* If *eval_str* is false (the default), values of type :class:`!str` are
unchanged.
*globals* and *locals* are passed in to :func:`eval`; see the documentation
for :func:`eval` for more information. If *globals* or *locals*
is :const:`!None`, this function may replace that value with a
context-specific default, contingent on ``type(obj)``:
* If *obj* is a module, *globals* defaults to ``obj.__dict__``.
* If *obj* is a class, *globals* defaults to
``sys.modules[obj.__module__].__dict__`` and *locals* defaults
to the *obj* class namespace.
* If *obj* is a callable, *globals* defaults to
:attr:`obj.__globals__ <function.__globals__>`,
although if *obj* is a wrapped function (using
:func:`functools.update_wrapper`) or a :class:`functools.partial` object,
it is unwrapped until a non-wrapped function is found.
Calling :func:`!get_annotations` is best practice for accessing the
annotations dict of any object. See :ref:`annotations-howto` for
more information on annotations best practices.
.. doctest::
>>> def f(a: int, b: str) -> float:
... pass
>>> get_annotations(f)
{'a': <class 'int'>, 'b': <class 'str'>, 'return': <class 'float'>}
.. versionadded:: 3.14

View File

@ -718,19 +718,19 @@ function.
Accepts a wide range of Python callables, from plain functions and classes to Accepts a wide range of Python callables, from plain functions and classes to
:func:`functools.partial` objects. :func:`functools.partial` objects.
For objects defined in modules using stringized annotations If some of the annotations are strings (e.g., because
(``from __future__ import annotations``), :func:`signature` will ``from __future__ import annotations`` was used), :func:`signature` will
attempt to automatically un-stringize the annotations using attempt to automatically un-stringize the annotations using
:func:`get_annotations`. The :func:`annotationlib.get_annotations`. The
*globals*, *locals*, and *eval_str* parameters are passed *globals*, *locals*, and *eval_str* parameters are passed
into :func:`get_annotations` when resolving the into :func:`!annotationlib.get_annotations` when resolving the
annotations; see the documentation for :func:`get_annotations` annotations; see the documentation for :func:`!annotationlib.get_annotations`
for instructions on how to use these parameters. for instructions on how to use these parameters.
Raises :exc:`ValueError` if no signature can be provided, and Raises :exc:`ValueError` if no signature can be provided, and
:exc:`TypeError` if that type of object is not supported. Also, :exc:`TypeError` if that type of object is not supported. Also,
if the annotations are stringized, and *eval_str* is not false, if the annotations are stringized, and *eval_str* is not false,
the ``eval()`` call(s) to un-stringize the annotations in :func:`get_annotations` the ``eval()`` call(s) to un-stringize the annotations in :func:`annotationlib.get_annotations`
could potentially raise any kind of exception. could potentially raise any kind of exception.
A slash(/) in the signature of a function denotes that the parameters prior A slash(/) in the signature of a function denotes that the parameters prior
@ -1247,62 +1247,19 @@ Classes and functions
.. versionadded:: 3.4 .. versionadded:: 3.4
.. function:: get_annotations(obj, *, globals=None, locals=None, eval_str=False) .. function:: get_annotations(obj, *, globals=None, locals=None, eval_str=False, format=annotationlib.Format.VALUE)
Compute the annotations dict for an object. Compute the annotations dict for an object.
``obj`` may be a callable, class, or module. This is an alias for :func:`annotationlib.get_annotations`; see the documentation
Passing in an object of any other type raises :exc:`TypeError`. of that function for more information.
Returns a dict. ``get_annotations()`` returns a new dict every time
it's called; calling it twice on the same object will return two
different but equivalent dicts.
This function handles several details for you:
* If ``eval_str`` is true, values of type ``str`` will
be un-stringized using :func:`eval`. This is intended
for use with stringized annotations
(``from __future__ import annotations``).
* If ``obj`` doesn't have an annotations dict, returns an
empty dict. (Functions and methods always have an
annotations dict; classes, modules, and other types of
callables may not.)
* Ignores inherited annotations on classes. If a class
doesn't have its own annotations dict, returns an empty dict.
* All accesses to object members and dict values are done
using ``getattr()`` and ``dict.get()`` for safety.
* Always, always, always returns a freshly created dict.
``eval_str`` controls whether or not values of type ``str`` are replaced
with the result of calling :func:`eval` on those values:
* If eval_str is true, :func:`eval` is called on values of type ``str``.
(Note that ``get_annotations`` doesn't catch exceptions; if :func:`eval`
raises an exception, it will unwind the stack past the ``get_annotations``
call.)
* If eval_str is false (the default), values of type ``str`` are unchanged.
``globals`` and ``locals`` are passed in to :func:`eval`; see the documentation
for :func:`eval` for more information. If ``globals`` or ``locals``
is ``None``, this function may replace that value with a context-specific
default, contingent on ``type(obj)``:
* If ``obj`` is a module, ``globals`` defaults to ``obj.__dict__``.
* If ``obj`` is a class, ``globals`` defaults to
``sys.modules[obj.__module__].__dict__`` and ``locals`` defaults
to the ``obj`` class namespace.
* If ``obj`` is a callable, ``globals`` defaults to
:attr:`obj.__globals__ <function.__globals__>`,
although if ``obj`` is a wrapped function (using
:func:`functools.update_wrapper`) it is first unwrapped.
Calling ``get_annotations`` is best practice for accessing the
annotations dict of any object. See :ref:`annotations-howto` for
more information on annotations best practices.
.. versionadded:: 3.10 .. versionadded:: 3.10
.. versionchanged:: 3.14
This function is now an alias for :func:`annotationlib.get_annotations`.
Calling it as ``inspect.get_annotations`` will continue to work.
.. _inspect-stack: .. _inspect-stack:

View File

@ -25,4 +25,5 @@ overview:
__future__.rst __future__.rst
gc.rst gc.rst
inspect.rst inspect.rst
annotationlib.rst
site.rst site.rst

View File

@ -1825,6 +1825,16 @@ without the dedicated syntax, as documented below.
the bound is evaluated only when the attribute is accessed, not when the bound is evaluated only when the attribute is accessed, not when
the type variable is created (see :ref:`lazy-evaluation`). the type variable is created (see :ref:`lazy-evaluation`).
.. method:: evaluate_bound
An :term:`evaluate function` corresponding to the :attr:`~TypeVar.__bound__` attribute.
When called directly, this method supports only the :attr:`~annotationlib.Format.VALUE`
format, which is equivalent to accessing the :attr:`~TypeVar.__bound__` attribute directly,
but the method object can be passed to :func:`annotationlib.call_evaluate_function`
to evaluate the value in a different format.
.. versionadded:: 3.14
.. attribute:: __constraints__ .. attribute:: __constraints__
A tuple containing the constraints of the type variable, if any. A tuple containing the constraints of the type variable, if any.
@ -1835,6 +1845,16 @@ without the dedicated syntax, as documented below.
the constraints are evaluated only when the attribute is accessed, not when the constraints are evaluated only when the attribute is accessed, not when
the type variable is created (see :ref:`lazy-evaluation`). the type variable is created (see :ref:`lazy-evaluation`).
.. method:: evaluate_constraints
An :term:`evaluate function` corresponding to the :attr:`~TypeVar.__constraints__` attribute.
When called directly, this method supports only the :attr:`~annotationlib.Format.VALUE`
format, which is equivalent to accessing the :attr:`~TypeVar.__constraints__` attribute directly,
but the method object can be passed to :func:`annotationlib.call_evaluate_function`
to evaluate the value in a different format.
.. versionadded:: 3.14
.. attribute:: __default__ .. attribute:: __default__
The default value of the type variable, or :data:`typing.NoDefault` if it The default value of the type variable, or :data:`typing.NoDefault` if it
@ -1842,6 +1862,16 @@ without the dedicated syntax, as documented below.
.. versionadded:: 3.13 .. versionadded:: 3.13
.. method:: evaluate_default
An :term:`evaluate function` corresponding to the :attr:`~TypeVar.__default__` attribute.
When called directly, this method supports only the :attr:`~annotationlib.Format.VALUE`
format, which is equivalent to accessing the :attr:`~TypeVar.__default__` attribute directly,
but the method object can be passed to :func:`annotationlib.call_evaluate_function`
to evaluate the value in a different format.
.. versionadded:: 3.14
.. method:: has_default() .. method:: has_default()
Return whether or not the type variable has a default value. This is equivalent Return whether or not the type variable has a default value. This is equivalent
@ -1980,6 +2010,16 @@ without the dedicated syntax, as documented below.
.. versionadded:: 3.13 .. versionadded:: 3.13
.. method:: evaluate_default
An :term:`evaluate function` corresponding to the :attr:`~TypeVarTuple.__default__` attribute.
When called directly, this method supports only the :attr:`~annotationlib.Format.VALUE`
format, which is equivalent to accessing the :attr:`~TypeVarTuple.__default__` attribute directly,
but the method object can be passed to :func:`annotationlib.call_evaluate_function`
to evaluate the value in a different format.
.. versionadded:: 3.14
.. method:: has_default() .. method:: has_default()
Return whether or not the type variable tuple has a default value. This is equivalent Return whether or not the type variable tuple has a default value. This is equivalent
@ -2076,6 +2116,16 @@ without the dedicated syntax, as documented below.
.. versionadded:: 3.13 .. versionadded:: 3.13
.. method:: evaluate_default
An :term:`evaluate function` corresponding to the :attr:`~ParamSpec.__default__` attribute.
When called directly, this method supports only the :attr:`~annotationlib.Format.VALUE`
format, which is equivalent to accessing the :attr:`~ParamSpec.__default__` attribute directly,
but the method object can be passed to :func:`annotationlib.call_evaluate_function`
to evaluate the value in a different format.
.. versionadded:: 3.14
.. method:: has_default() .. method:: has_default()
Return whether or not the parameter specification has a default value. This is equivalent Return whether or not the parameter specification has a default value. This is equivalent
@ -2200,6 +2250,32 @@ without the dedicated syntax, as documented below.
>>> Recursive.__value__ >>> Recursive.__value__
Mutually Mutually
.. method:: evaluate_value
An :term:`evaluate function` corresponding to the :attr:`__value__` attribute.
When called directly, this method supports only the :attr:`~annotationlib.Format.VALUE`
format, which is equivalent to accessing the :attr:`__value__` attribute directly,
but the method object can be passed to :func:`annotationlib.call_evaluate_function`
to evaluate the value in a different format:
.. doctest::
>>> type Alias = undefined
>>> Alias.__value__
Traceback (most recent call last):
...
NameError: name 'undefined' is not defined
>>> from annotationlib import Format, call_evaluate_function
>>> Alias.evaluate_value(Format.VALUE)
Traceback (most recent call last):
...
NameError: name 'undefined' is not defined
>>> call_evaluate_function(Alias.evaluate_value, Format.FORWARDREF)
ForwardRef('undefined')
.. versionadded:: 3.14
Other special directives Other special directives
"""""""""""""""""""""""" """"""""""""""""""""""""
@ -3306,7 +3382,7 @@ Introspection helpers
Class used for internal typing representation of string forward references. Class used for internal typing representation of string forward references.
For example, ``List["SomeClass"]`` is implicitly transformed into For example, ``List["SomeClass"]`` is implicitly transformed into
``List[ForwardRef("SomeClass")]``. ``ForwardRef`` should not be instantiated by ``List[ForwardRef("SomeClass")]``. :class:`!ForwardRef` should not be instantiated by
a user, but may be used by introspection tools. a user, but may be used by introspection tools.
.. note:: .. note::
@ -3316,6 +3392,39 @@ Introspection helpers
.. versionadded:: 3.7.4 .. versionadded:: 3.7.4
.. versionchanged:: 3.14
This is now an alias for :class:`annotationlib.ForwardRef`.
.. function:: evaluate_forward_ref(forward_ref, *, owner=None, globals=None, locals=None, type_params=None, format=annotationlib.Format.VALUE)
Evaluate an :class:`annotationlib.ForwardRef` as a :term:`type hint`.
This is similar to calling :meth:`annotationlib.ForwardRef.evaluate`,
but unlike that method, :func:`!evaluate_forward_ref` also:
* Recursively evaluates forward references nested within the type hint.
* Raises :exc:`TypeError` when it encounters certain objects that are
not valid type hints.
* Replaces type hints that evaluate to :const:`!None` with
:class:`types.NoneType`.
* Supports the :attr:`~annotationlib.Format.FORWARDREF` and
:attr:`~annotationlib.Format.SOURCE` formats.
*forward_ref* must be an instance of :class:`~annotationlib.ForwardRef`.
*owner*, if given, should be the object that holds the annotations that
the forward reference derived from, such as a module, class object, or function.
It is used to infer the namespaces to use for looking up names.
*globals* and *locals* can also be explicitly given to provide
the global and local namespaces.
*type_params* is a tuple of :ref:`type parameters <type-params>` that
are in scope when evaluating the forward reference.
This parameter must be provided (though it may be an empty tuple) if *owner*
is not given and the forward reference does not already have an owner set.
*format* specifies the format of the annotation and is a member of
the :class:`annotationlib.Format` enum.
.. versionadded:: 3.14
.. data:: NoDefault .. data:: NoDefault
A sentinel object used to indicate that a type parameter has no default A sentinel object used to indicate that a type parameter has no default

View File

@ -1329,13 +1329,7 @@ following the parameter name. Any parameter may have an annotation, even those
``*identifier`` or ``**identifier``. Functions may have "return" annotation of ``*identifier`` or ``**identifier``. Functions may have "return" annotation of
the form "``-> expression``" after the parameter list. These annotations can be the form "``-> expression``" after the parameter list. These annotations can be
any valid Python expression. The presence of annotations does not change the any valid Python expression. The presence of annotations does not change the
semantics of a function. The annotation values are available as values of semantics of a function. See :ref:`annotations` for more information on annotations.
a dictionary keyed by the parameters' names in the :attr:`__annotations__`
attribute of the function object. If the ``annotations`` import from
:mod:`__future__` is used, annotations are preserved as strings at runtime which
enables postponed evaluation. Otherwise, they are evaluated when the function
definition is executed. In this case annotations may be evaluated in
a different order than they appear in the source code.
.. index:: pair: lambda; expression .. index:: pair: lambda; expression
@ -1852,6 +1846,44 @@ Here, ``annotation-def`` (not a real keyword) indicates an
:ref:`annotation scope <annotation-scopes>`. The capitalized names :ref:`annotation scope <annotation-scopes>`. The capitalized names
like ``TYPE_PARAMS_OF_ListOrSet`` are not actually bound at runtime. like ``TYPE_PARAMS_OF_ListOrSet`` are not actually bound at runtime.
.. _annotations:
Annotations
===========
.. versionchanged:: 3.14
Annotations are now lazily evaluated by default.
Variables and function parameters may carry :term:`annotations <annotation>`,
created by adding a colon after the name, followed by an expression::
x: annotation = 1
def f(param: annotation): ...
Functions may also carry a return annotation following an arrow::
def f() -> annotation: ...
Annotations are conventionally used for :term:`type hints <type hint>`, but this
is not enforced by the language, and in general annotations may contain arbitrary
expressions. The presence of annotations does not change the runtime semantics of
the code, except if some mechanism is used that introspects and uses the annotations
(such as :mod:`dataclasses` or :func:`functools.singledispatch`).
By default, annotations are lazily evaluated in a :ref:`annotation scope <annotation-scopes>`.
This means that they are not evaluated when the code containing the annotation is evaluated.
Instead, the interpreter saves information that can be used to evaluate the annotation later
if requested. The :mod:`annotationlib` module provides tools for evaluating annotations.
If the :ref:`future statement <future>` ``from __future__ import annotations`` is present,
all annotations are instead stored as strings::
>>> from __future__ import annotations
>>> def f(param: annotation): ...
>>> f.__annotations__
{'param': 'annotation'}
.. rubric:: Footnotes .. rubric:: Footnotes
.. [#] The exception is propagated to the invocation stack unless .. [#] The exception is propagated to the invocation stack unless

View File

@ -581,6 +581,7 @@ Special writable attributes
single: __defaults__ (function attribute) single: __defaults__ (function attribute)
single: __code__ (function attribute) single: __code__ (function attribute)
single: __annotations__ (function attribute) single: __annotations__ (function attribute)
single: __annotate__ (function attribute)
single: __kwdefaults__ (function attribute) single: __kwdefaults__ (function attribute)
single: __type_params__ (function attribute) single: __type_params__ (function attribute)
@ -628,7 +629,17 @@ Most of these attributes check the type of the assigned value:
:term:`parameters <parameter>`. :term:`parameters <parameter>`.
The keys of the dictionary are the parameter names, The keys of the dictionary are the parameter names,
and ``'return'`` for the return annotation, if provided. and ``'return'`` for the return annotation, if provided.
See also: :ref:`annotations-howto`. See also: :attr:`object.__annotations__`.
.. versionchanged:: 3.14
Annotations are now :ref:`lazily evaluated <lazy-evaluation>`.
See :pep:`649`.
* - .. attribute:: function.__annotate__
- The :term:`annotate function` for this function, or ``None``
if the function has no annotations. See :attr:`object.__annotate__`.
.. versionadded:: 3.14
* - .. attribute:: function.__kwdefaults__ * - .. attribute:: function.__kwdefaults__
- A :class:`dictionary <dict>` containing defaults for keyword-only - A :class:`dictionary <dict>` containing defaults for keyword-only
@ -881,6 +892,7 @@ Attribute assignment updates the module's namespace dictionary, e.g.,
single: __doc__ (module attribute) single: __doc__ (module attribute)
single: __file__ (module attribute) single: __file__ (module attribute)
single: __annotations__ (module attribute) single: __annotations__ (module attribute)
single: __annotate__ (module attribute)
pair: module; namespace pair: module; namespace
Predefined (writable) attributes: Predefined (writable) attributes:
@ -901,11 +913,21 @@ Predefined (writable) attributes:
loaded dynamically from a shared library, it's the pathname of the shared loaded dynamically from a shared library, it's the pathname of the shared
library file. library file.
:attr:`__annotations__` :attr:`~object.__annotations__`
A dictionary containing A dictionary containing
:term:`variable annotations <variable annotation>` collected during :term:`variable annotations <variable annotation>` collected during
module body execution. For best practices on working module body execution. For best practices on working
with :attr:`__annotations__`, please see :ref:`annotations-howto`. with :attr:`!__annotations__`, see :mod:`annotationlib`.
.. versionchanged:: 3.14
Annotations are now :ref:`lazily evaluated <lazy-evaluation>`.
See :pep:`649`.
:attr:`~object.__annotate__`
The :term:`annotate function` for this module, or ``None``
if the module has no annotations. See :attr:`object.__annotate__`.
.. versionadded:: 3.14
.. index:: single: __dict__ (module attribute) .. index:: single: __dict__ (module attribute)
@ -969,6 +991,7 @@ A class object can be called (see above) to yield a class instance (see below).
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: __annotate__ (class attribute)
single: __type_params__ (class attribute) single: __type_params__ (class attribute)
single: __static_attributes__ (class attribute) single: __static_attributes__ (class attribute)
single: __firstlineno__ (class attribute) single: __firstlineno__ (class attribute)
@ -991,12 +1014,36 @@ Special attributes:
:attr:`__doc__` :attr:`__doc__`
The class's documentation string, or ``None`` if undefined. The class's documentation string, or ``None`` if undefined.
:attr:`__annotations__` :attr:`~object.__annotations__`
A dictionary containing A dictionary containing
:term:`variable annotations <variable annotation>` :term:`variable annotations <variable annotation>`
collected during class body execution. For best practices on collected during class body execution. For best practices on
working with :attr:`__annotations__`, please see working with :attr:`~object.__annotations__`, please see
:ref:`annotations-howto`. :mod:`annotationlib`.
.. warning::
Accessing the :attr:`~object.__annotations__` attribute of a class
object directly may yield incorrect results in the presence of
metaclasses. Use :func:`annotationlib.get_annotations` to
retrieve class annotations safely.
.. versionchanged:: 3.14
Annotations are now :ref:`lazily evaluated <lazy-evaluation>`.
See :pep:`649`.
:attr:`~object.__annotate__`
The :term:`annotate function` for this class, or ``None``
if the class has no annotations. See :attr:`object.__annotate__`.
.. warning::
Accessing the :attr:`~object.__annotate__` attribute of a class
object directly may yield incorrect results in the presence of
metaclasses. Use :func:`annotationlib.get_annotate_function` to
retrieve the annotate function safely.
.. versionadded:: 3.14
:attr:`__type_params__` :attr:`__type_params__`
A tuple containing the :ref:`type parameters <type-params>` of A tuple containing the :ref:`type parameters <type-params>` of
@ -3253,6 +3300,51 @@ implement the protocol in Python.
:class:`collections.abc.Buffer` :class:`collections.abc.Buffer`
ABC for buffer types. ABC for buffer types.
Annotations
-----------
Functions, classes, and modules may contain :term:`annotations <annotation>`,
which are a way to associate information (usually :term:`type hints <type hint>`)
with a symbol.
.. attribute:: object.__annotations__
This attribute contains the annotations for an object. It is
:ref:`lazily evaluated <lazy-evaluation>`, so accessing the attribute may
execute arbitrary code and raise exceptions. If evaluation is successful, the
attribute is set to a dictionary mapping from variable names to annotations.
.. versionchanged:: 3.14
Annotations are now lazily evaluated.
.. method:: object.__annotate__(format)
An :term:`annotate function`.
Returns a new dictionary object mapping attribute/parameter names to their annotation values.
Takes a format parameter specifying the format in which annotations values should be provided.
It must be a member of the :class:`annotationlib.Format` enum, or an integer with
a value corresponding to a member of the enum.
If an annotate function doesn't support the requested format, it must raise
:exc:`NotImplementedError`. Annotate functions must always support
:attr:`~annotationlib.Format.VALUE` format; they must not raise
:exc:`NotImplementedError()` when called with this format.
When called with :attr:`~annotationlib.Format.VALUE` format, an annotate function may raise
:exc:`NameError`; it must not raise :exc:`!NameError` when called requesting any other format.
If an object does not have any annotations, :attr:`~object.__annotate__` should preferably be set
to ``None`` (it cant be deleted), rather than set to a function that returns an empty dict.
.. versionadded:: 3.14
.. seealso::
:pep:`649` --- Deferred evaluation of annotation using descriptors
Introduces lazy evaluation of annotations and the ``__annotate__`` function.
.. _special-lookup: .. _special-lookup:
Special method lookup Special method lookup

View File

@ -190,14 +190,15 @@ However, the following will succeed::
Annotation scopes Annotation scopes
----------------- -----------------
:ref:`Type parameter lists <type-params>` and :keyword:`type` statements :term:`Annotations <annotation>`, :ref:`type parameter lists <type-params>`
and :keyword:`type` statements
introduce *annotation scopes*, which behave mostly like function scopes, introduce *annotation scopes*, which behave mostly like function scopes,
but with some exceptions discussed below. :term:`Annotations <annotation>` but with some exceptions discussed below.
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: Annotation scopes are used in the following contexts:
* :term:`Function annotations <function annotation>`.
* :term:`Variable annotations <variable annotation>`.
* Type parameter lists for :ref:`generic type aliases <generic-type-aliases>`. * Type parameter lists for :ref:`generic type aliases <generic-type-aliases>`.
* Type parameter lists for :ref:`generic functions <generic-functions>`. * Type parameter lists for :ref:`generic functions <generic-functions>`.
A generic function's annotations are A generic function's annotations are
@ -236,17 +237,23 @@ Annotation scopes differ from function scopes in the following ways:
Annotation scopes are also used for type parameter defaults, as Annotation scopes are also used for type parameter defaults, as
introduced by :pep:`696`. introduced by :pep:`696`.
.. versionchanged:: 3.14
Annotation scopes are now also used for annotations, as specified in
:pep:`649` and :pep:`749`.
.. _lazy-evaluation: .. _lazy-evaluation:
Lazy evaluation Lazy evaluation
--------------- ---------------
The values of type aliases created through the :keyword:`type` statement are Most annotation scopes are *lazily evaluated*. This includes annotations,
*lazily evaluated*. The same applies to the bounds, constraints, and default values of type the values of type aliases created through the :keyword:`type` statement, and
the bounds, constraints, and default values of type
variables created through the :ref:`type parameter syntax <type-params>`. 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 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 created, or when the object carrying annotations is created. Instead, they
an attribute access. are only evaluated when necessary, for example when the ``__value__``
attribute on a type alias is accessed.
Example: Example:

View File

@ -336,23 +336,21 @@ The difference from normal :ref:`assignment` is that only a single target is all
The assignment target is considered "simple" if it consists of a single The assignment target is considered "simple" if it consists of a single
name that is not enclosed in parentheses. name that is not enclosed in parentheses.
For simple assignment targets, if in class or module scope, For simple assignment targets, if in class or module scope,
the annotations are evaluated and stored in a special class or module the annotations are gathered in a lazily evaluated
attribute :attr:`__annotations__` :ref:`annotation scope <annotation-scopes>`. The annotations can be
that is a dictionary mapping from variable names (mangled if private) to evaluated using the :attr:`~object.__annotations__` attribute of a
evaluated annotations. This attribute is writable and is automatically class or module, or using the facilities in the :mod:`annotationlib`
created at the start of class or module body execution, if annotations module.
are found statically.
If the assignment target is not simple (an attribute, subscript node, or If the assignment target is not simple (an attribute, subscript node, or
parenthesized name), the annotation is evaluated if parenthesized name), the annotation is never evaluated.
in class or module scope, but not stored.
If a name is annotated in a function scope, then this name is local for If a name is annotated in a function scope, then this name is local for
that scope. Annotations are never evaluated and stored in function scopes. that scope. Annotations are never evaluated and stored in function scopes.
If the right hand side is present, an annotated If the right hand side is present, an annotated
assignment performs the actual assignment before evaluating annotations assignment performs the actual assignment as if there was no annotation
(where applicable). If the right hand side is not present for an expression present. If the right hand side is not present for an expression
target, then the interpreter evaluates the target except for the last target, then the interpreter evaluates the target except for the last
:meth:`~object.__setitem__` or :meth:`~object.__setattr__` call. :meth:`~object.__setitem__` or :meth:`~object.__setattr__` call.
@ -373,6 +371,10 @@ target, then the interpreter evaluates the target except for the last
regular assignments. Previously, some expressions (like un-parenthesized regular assignments. Previously, some expressions (like un-parenthesized
tuple expressions) caused a syntax error. tuple expressions) caused a syntax error.
.. versionchanged:: 3.14
Annotations are now lazily evaluated in a separate :ref:`annotation scope <annotation-scopes>`.
If the assignment target is not simple, annotations are never evaluated.
.. _assert: .. _assert:
@ -975,8 +977,8 @@ block textually preceding that :keyword:`!global` statement.
Names listed in a :keyword:`global` statement must not be defined as formal Names listed in a :keyword:`global` statement must not be defined as formal
parameters, or as targets in :keyword:`with` statements or :keyword:`except` clauses, or in a :keyword:`for` target list, :keyword:`class` parameters, or as targets in :keyword:`with` statements or :keyword:`except` clauses, or in a :keyword:`for` target list, :keyword:`class`
definition, function definition, :keyword:`import` statement, or variable definition, function definition, :keyword:`import` statement, or
annotation. :term:`variable annotations <variable annotation>`.
.. impl-detail:: .. impl-detail::