summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Doc/c-api/reflection.rst27
-rw-r--r--Doc/reference/datamodel.rst4
-rw-r--r--Doc/whatsnew/3.13.rst36
3 files changed, 46 insertions, 21 deletions
diff --git a/Doc/c-api/reflection.rst b/Doc/c-api/reflection.rst
index af9a1a7..038e697 100644
--- a/Doc/c-api/reflection.rst
+++ b/Doc/c-api/reflection.rst
@@ -19,23 +19,28 @@ Reflection
.. deprecated:: 3.13
- To avoid creating a reference cycle in :term:`optimized scopes <optimized scope>`,
- use either :c:func:`PyEval_GetFrameLocals` to obtain the same behaviour as calling
+ Use either :c:func:`PyEval_GetFrameLocals` to obtain the same behaviour as calling
:func:`locals` in Python code, or else call :c:func:`PyFrame_GetLocals` on the result
- of :c:func:`PyEval_GetFrame` to get the same result as this function without having to
- cache the proxy instance on the underlying frame.
+ of :c:func:`PyEval_GetFrame` to access the :attr:`~frame.f_locals` attribute of the
+ currently executing frame.
- Return the :attr:`~frame.f_locals` attribute of the currently executing frame,
+ Return a mapping providing access to the local variables in the current execution frame,
or ``NULL`` if no frame is currently executing.
- If the frame refers to an :term:`optimized scope`, this returns a
- write-through proxy object that allows modifying the locals.
- In all other cases (classes, modules, :func:`exec`, :func:`eval`) it returns
- the mapping representing the frame locals directly (as described for
- :func:`locals`).
+ Refer to :func:`locals` for details of the mapping returned at different scopes.
+
+ As this function returns a :term:`borrowed reference`, the dictionary returned for
+ :term:`optimized scopes <optimized scope>` is cached on the frame object and will remain
+ alive as long as the frame object does. Unlike :c:func:`PyEval_GetFrameLocals` and
+ :func:`locals`, subsequent calls to this function in the same frame will update the
+ contents of the cached dictionary to reflect changes in the state of the local variables
+ rather than returning a new snapshot.
.. versionchanged:: 3.13
- As part of :pep:`667`, return a proxy object for optimized scopes.
+ As part of :pep:`667`, :c:func:`PyFrame_GetLocals`, :func:`locals`, and
+ :attr:`FrameType.f_locals <frame.f_locals>` no longer make use of the shared cache
+ dictionary. Refer to the :ref:`What's New entry <whatsnew313-locals-semantics>` for
+ additional details.
.. c:function:: PyObject* PyEval_GetGlobals(void)
diff --git a/Doc/reference/datamodel.rst b/Doc/reference/datamodel.rst
index 134385e..9110060 100644
--- a/Doc/reference/datamodel.rst
+++ b/Doc/reference/datamodel.rst
@@ -1347,13 +1347,13 @@ Special read-only attributes
``object.__getattr__`` with arguments ``obj`` and ``"f_code"``.
* - .. attribute:: frame.f_locals
- - The dictionary used by the frame to look up
+ - The mapping used by the frame to look up
:ref:`local variables <naming>`.
If the frame refers to an :term:`optimized scope`,
this may return a write-through proxy object.
.. versionchanged:: 3.13
- Return a proxy for functions and comprehensions.
+ Return a proxy for optimized scopes.
* - .. attribute:: frame.f_globals
- The dictionary used by the frame to look up
diff --git a/Doc/whatsnew/3.13.rst b/Doc/whatsnew/3.13.rst
index ab260bf..66626ac 100644
--- a/Doc/whatsnew/3.13.rst
+++ b/Doc/whatsnew/3.13.rst
@@ -287,8 +287,9 @@ returns a write-through proxy to the frame's local and locally referenced
nonlocal variables in these scopes, rather than returning an inconsistently
updated shared ``dict`` instance with undefined runtime semantics.
-See :pep:`667` for more details, including related C API changes and
-deprecations.
+See :pep:`667` for more details, including related C API changes and deprecations. Porting
+notes are also provided below for the affected :ref:`Python APIs <pep667-porting-notes-py>`
+and :ref:`C APIs <pep667-porting-notes-c>`.
(PEP and implementation contributed by Mark Shannon and Tian Gao in
:gh:`74929`. Documentation updates provided by Guido van Rossum and
@@ -2246,6 +2247,8 @@ Changes in the Python API
returned by :meth:`zipfile.ZipFile.open` was changed from ``'r'`` to ``'rb'``.
(Contributed by Serhiy Storchaka in :gh:`115961`.)
+.. _pep667-porting-notes-py:
+
* Calling :func:`locals` in an :term:`optimized scope` now produces an
independent snapshot on each call, and hence no longer implicitly updates
previously returned references. Obtaining the legacy CPython behaviour now
@@ -2341,15 +2344,27 @@ Changes in the C API
to :c:func:`PyUnstable_Code_GetFirstFree`.
(Contributed by Bogdan Romanyuk in :gh:`115781`.)
-* Calling :c:func:`PyFrame_GetLocals` or :c:func:`PyEval_GetLocals` in an
- :term:`optimized scope` now returns a write-through proxy rather than a
- snapshot that gets updated at ill-specified times. If a snapshot is desired,
- it must be created explicitly (e.g. with :c:func:`PyDict_Copy`) or by calling
- the new :c:func:`PyEval_GetFrameLocals` API. (Changed as part of :pep:`667`.)
+.. _pep667-porting-notes-c:
+
+* The effects of mutating the dictionary returned from :c:func:`PyEval_GetLocals` in an
+ :term:`optimized scope` have changed. New dict entries added this way will now *only* be
+ visible to subsequent :c:func:`PyEval_GetLocals` calls in that frame, as
+ :c:func:`PyFrame_GetLocals`, :func:`locals`, and
+ :attr:`FrameType.f_locals <frame.f_locals>` no longer access the same underlying cached
+ dictionary. Changes made to entries for actual variable names and names added via the
+ write-through proxy interfaces will be overwritten on subsequent calls to
+ :c:func:`PyEval_GetLocals` in that frame. The recommended code update depends on how the
+ function was being used, so refer to the deprecation notice on the function for details.
+ (Changed as part of :pep:`667`.)
+
+* Calling :c:func:`PyFrame_GetLocals` in an :term:`optimized scope` now returns a
+ write-through proxy rather than a snapshot that gets updated at ill-specified times.
+ If a snapshot is desired, it must be created explicitly (e.g. with :c:func:`PyDict_Copy`)
+ or by calling the new :c:func:`PyEval_GetFrameLocals` API. (Changed as part of :pep:`667`.)
* :c:func:`!PyFrame_FastToLocals` and :c:func:`!PyFrame_FastToLocalsWithError`
no longer have any effect. Calling these functions has been redundant since
- Python 3.11, when :c:func:`PyFrame_GetLocals` was first introduced.
+ Python 3.11, when :c:func:`PyFrame_GetLocals` was first introduced.
(Changed as part of :pep:`667`.)
* :c:func:`!PyFrame_LocalsToFast` no longer has any effect. Calling this function
@@ -2509,6 +2524,11 @@ Deprecated C APIs
:c:func:`PyWeakref_GetRef` on Python 3.12 and older.
(Contributed by Victor Stinner in :gh:`105927`.)
+* Deprecate the :c:func:`PyEval_GetBuiltins`, :c:func:`PyEval_GetGlobals`, and
+ :c:func:`PyEval_GetLocals` functions, which return a :term:`borrowed reference`.
+ Refer to the deprecation notices on each function for their recommended replacements.
+ (Soft deprecated as part of :pep:`667`.)
+
Pending Removal in Python 3.14
------------------------------