mirror of
https://github.com/python/cpython.git
synced 2025-08-31 14:07:50 +00:00
[3.13] gh-118888: Further PEP 667 docs updates (gh-119894)
* Clarify impact on default behaviour of exec, eval, etc
* Update documentation for changes to PyEval_GetLocals (gh-74929)
Closes gh-118888
(cherry picked from commit 2180991ea3
)
Co-authored-by: Alyssa Coghlan <ncoghlan@gmail.com>
This commit is contained in:
parent
edb6883ef3
commit
36ca00f44d
2 changed files with 44 additions and 3 deletions
|
@ -19,11 +19,24 @@ Reflection
|
|||
|
||||
.. deprecated:: 3.13
|
||||
|
||||
Use :c:func:`PyEval_GetFrameLocals` instead.
|
||||
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
|
||||
: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.
|
||||
|
||||
Return a dictionary of the local variables in the current execution frame,
|
||||
Return the :attr:`~frame.f_locals` attribute of the currently executing 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`).
|
||||
|
||||
.. versionchanged:: 3.13
|
||||
As part of :pep:`667`, return a proxy object for optimized scopes.
|
||||
|
||||
|
||||
.. c:function:: PyObject* PyEval_GetGlobals(void)
|
||||
|
||||
|
@ -57,6 +70,10 @@ Reflection
|
|||
or ``NULL`` if no frame is currently executing. Equivalent to calling
|
||||
:func:`locals` in Python code.
|
||||
|
||||
To access :attr:`~frame.f_locals` on the current frame without making an independent
|
||||
snapshot in :term:`optimized scopes <optimized scope>`, call :c:func:`PyFrame_GetLocals`
|
||||
on the result of :c:func:`PyEval_GetFrame`.
|
||||
|
||||
.. versionadded:: 3.13
|
||||
|
||||
|
||||
|
|
|
@ -266,6 +266,21 @@ comprehensions, and generator expressions) to explicitly return independent
|
|||
snapshots of the currently assigned local variables, including locally
|
||||
referenced nonlocal variables captured in closures.
|
||||
|
||||
This change to the semantics of :func:`locals` in optimized scopes also affects the default
|
||||
behaviour of code execution functions that implicitly target ``locals()`` if no explicit
|
||||
namespace is provided (such as :func:`exec` and :func:`eval`). In previous versions, whether
|
||||
or not changes could be accessed by calling ``locals()`` after calling the code execution
|
||||
function was implementation dependent. In CPython specifically, such code would typically
|
||||
appear to work as desired, but could sometimes fail in optimized scopes based on other code
|
||||
(including debuggers and code execution tracing tools) potentially resetting the shared
|
||||
snapshot in that scope. Now, the code will always run against an independent snapshot of the
|
||||
local variables in optimized scopes, and hence the changes will never be visible in
|
||||
subsequent calls to ``locals()``. To access the changes made in these cases, an explicit
|
||||
namespace reference must now be passed to the relevant function. Alternatively, it may make
|
||||
sense to update affected code to use a higher level code execution API that returns the
|
||||
resulting code execution namespace (e.g. :func:`runpy.run_path` when executing Python
|
||||
files from disk).
|
||||
|
||||
To ensure debuggers and similar tools can reliably update local variables in
|
||||
scopes affected by this change, :attr:`FrameType.f_locals <frame.f_locals>` now
|
||||
returns a write-through proxy to the frame's local and locally referenced
|
||||
|
@ -2223,7 +2238,10 @@ Changes in the Python API
|
|||
independent snapshot on each call, and hence no longer implicitly updates
|
||||
previously returned references. Obtaining the legacy CPython behaviour now
|
||||
requires explicit calls to update the initially returned dictionary with the
|
||||
results of subsequent calls to ``locals()``. (Changed as part of :pep:`667`.)
|
||||
results of subsequent calls to ``locals()``. Code execution functions that
|
||||
implicitly target ``locals()`` (such as ``exec`` and ``eval``) must be
|
||||
passed an explicit namespace to access their results in an optimized scope.
|
||||
(Changed as part of :pep:`667`.)
|
||||
|
||||
* Calling :func:`locals` from a comprehension at module or class scope
|
||||
(including via ``exec`` or ``eval``) once more behaves as if the comprehension
|
||||
|
@ -2311,6 +2329,12 @@ 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`.)
|
||||
|
||||
* :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.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue