Skip to content

gh-74929: PEP 667 general docs update #119201

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 20 commits into from
May 21, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Define 'optimised scope' term, review f_locals
  • Loading branch information
ncoghlan committed May 20, 2024
commit b95890daeb18763c7355b3ee85685520809388a2
6 changes: 3 additions & 3 deletions Doc/c-api/frame.rst
Original file line number Diff line number Diff line change
Expand Up @@ -121,8 +121,8 @@ See also :ref:`Reflection <reflection>`.
.. c:function:: PyObject* PyFrame_GetLocals(PyFrameObject *frame)

Get the *frame*'s :attr:`~frame.f_locals` attribute.
If the frame refers to a function or comprehension, this returns
a write-through proxy object that allows modifying the locals.
If the frame refers to an :term:`optimised 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`).
Expand All @@ -132,7 +132,7 @@ See also :ref:`Reflection <reflection>`.
.. versionadded:: 3.11

.. versionchanged:: 3.13
Return a proxy object for functions and comprehensions.
As part of :pep:`667`, return a proxy object for optimised scopes.


.. c:function:: int PyFrame_GetLineNumber(PyFrameObject *frame)
Expand Down
7 changes: 7 additions & 0 deletions Doc/glossary.rst
Original file line number Diff line number Diff line change
Expand Up @@ -889,6 +889,13 @@ Glossary
(methods). Also the ultimate base class of any :term:`new-style
class`.

optimised scope
A scope where target local variable names are reliably known to the
compiler when the code is compiled, allowing optimisation of read and
write access to these names. The local namespaces for functions,
generators, coroutines, comprehensions, and generator expressions are
optimised.

package
A Python :term:`module` which can contain submodules or recursively,
subpackages. Technically, a package is a Python module with a
Expand Down
17 changes: 8 additions & 9 deletions Doc/library/functions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1080,14 +1080,14 @@ are always available. They are listed here in alphabetical order.
deleting local variables will immediately affect the contents of the
returned mapping object.

At function scope (including for generators and coroutines), each call to
``locals()`` instead returns a fresh dictionary containing the current
bindings of the function's local variables and any nonlocal cell references.
In this case, name binding changes made via the returned dict are *not*
written back to the corresponding local variables or nonlocal cell
references, and binding, rebinding, or deleting local variables and nonlocal
cell references does *not* affect the contents of previously returned
dictionaries.
In an :term:`optimised scope` (including functions, generators, and
coroutines), each call to ``locals()`` instead returns a fresh dictionary
containing the current bindings of the function's local variables and any
nonlocal cell references. In this case, name binding changes made via the
returned dict are *not* written back to the corresponding local variables
or nonlocal cell references, and assigning, reassigning, or deleting local
variables and nonlocal cell references does *not* affect the contents
of previously returned dictionaries.

Calling ``locals()`` as part of a comprehension in a function, generator, or
coroutine is equivalent to calling it in the containing scope, except that
Expand All @@ -1098,7 +1098,6 @@ are always available. They are listed here in alphabetical order.
Calling ``locals()`` as part of a generator expression is equivalent to
calling it in a nested generator function.


.. versionchanged:: 3.13
As part of :pep:`667`, the semantics of mutating the mapping object
returned from this function are now formally defined. The behavior in
Expand Down
2 changes: 1 addition & 1 deletion Doc/reference/datamodel.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1349,7 +1349,7 @@ Special read-only attributes
* - .. attribute:: frame.f_locals
- The dictionary used by the frame to look up
:ref:`local variables <naming>`.
If the frame refers to a function or comprehension,
If the frame refers to an :term:`optimised scope`,
this may return a write-through proxy object.

.. versionchanged:: 3.13
Expand Down
11 changes: 5 additions & 6 deletions Doc/whatsnew/3.13.rst
Original file line number Diff line number Diff line change
Expand Up @@ -378,10 +378,11 @@ Historically, the semantics for mutating the return value of :func:`locals` have
been left to individual Python implementations to define.

Through :pep:`667`, Python 3.13 standardises the historical behaviour of CPython
for most code execution scopes, but changes optimised scopes (functions,
generators, coroutines, comprehensions, and generator expressions) to explicitly
return independent snapshots of the currently assigned local variables, included
locally referenced nonlocal variables captured in closures.
for most code execution scopes, but changes
:term:`optimised scopes <optimised scope>` (functions, generators, coroutines,
comprehensions, and generator expressions) to explicitly return independent
snapshots of the currently assigned local variables, including locally
referenced nonlocal variables captured in closures.

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
Expand All @@ -392,8 +393,6 @@ updated shared ``dict`` instance with undefined runtime semantics.
See :pep:`667` for more details, including related C API changes and
deprecations.

.. todo: Add notes to porting guide


Other Language Changes
======================
Expand Down
9 changes: 6 additions & 3 deletions Lib/pdb.py
Original file line number Diff line number Diff line change
Expand Up @@ -392,9 +392,12 @@ def setup(self, f, tb):
self.tb_lineno[tb.tb_frame] = lineno
tb = tb.tb_next
self.curframe = self.stack[self.curindex][0]
# The f_locals dictionary is updated from the actual frame
# locals whenever the .f_locals accessor is called, so we
# cache it here to ensure that modifications are not overwritten.
# The f_locals dictionary used to be updated from the actual frame
# locals whenever the .f_locals accessor was called, so it was
# cached here to ensure that modifications were not overwritten. While
# the caching is no longer required now that f_locals is a direct proxy
# on optimised frames, it's also harmless, so the code structure has
# been left unchanged.
self.curframe_locals = self.curframe.f_locals
self.set_convenience_variable(self.curframe, '_frame', self.curframe)

Expand Down