From c843d7bdc926aee887b5a6053d566d22845e3c54 Mon Sep 17 00:00:00 2001 From: Alyssa Coghlan Date: Thu, 25 Apr 2024 14:31:48 +1000 Subject: [PATCH 1/2] locals() docs update for PEP 667 Proposed documentation wording taken from the withdrawn PEP 558 (which had switched to the Python level semantics proposed in PEP 667 prior to its withdrawal). --- Doc/library/functions.rst | 38 +++++++++++++++++++++++++++++--------- 1 file changed, 29 insertions(+), 9 deletions(-) diff --git a/Doc/library/functions.rst b/Doc/library/functions.rst index e598ef423de497..d58e4099620445 100644 --- a/Doc/library/functions.rst +++ b/Doc/library/functions.rst @@ -632,8 +632,7 @@ are always available. They are listed here in alphabetical order. .. note:: - The default *locals* act as described for function :func:`locals` below: - modifications to the default *locals* dictionary should not be attempted. + The default *locals* act as described for function :func:`locals` below. Pass an explicit *locals* dictionary if you need to see effects of the code on *locals* after function :func:`exec` returns. @@ -1041,14 +1040,35 @@ are always available. They are listed here in alphabetical order. .. function:: locals() - Update and return a dictionary representing the current local symbol table. - Free variables are returned by :func:`locals` when it is called in function - blocks, but not in class blocks. Note that at the module level, :func:`locals` - and :func:`globals` are the same dictionary. + Return a mapping object representing the current local symbol table, with + variable names as the keys, and their currently bound references as the + values. + + At module scope, as well as when using ``exec()`` or ``eval()`` with a + single namespace, this function returns the same namespace as ``globals()``. + + At class scope, it returns the namespace that will be passed to the + metaclass constructor. + + When using ``exec()`` or ``eval()`` with separate local and global + namespaces, it returns the local namespace passed in to the function call. + + In all of the above cases, each call to ``locals()`` in a given frame of + execution will return the *same* mapping object. Changes made through + the mapping object returned from ``locals()`` will be visible as bound, + rebound, or deleted local variables, and binding, rebinding, or 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. - .. note:: - The contents of this dictionary should not be modified; changes may not - affect the values of local and free variables used by the interpreter. .. function:: map(function, iterable, *iterables) From 0e290f57cdc5eadd67df69f360c20cd06ba7bb7e Mon Sep 17 00:00:00 2001 From: Alyssa Coghlan Date: Sun, 28 Apr 2024 20:13:23 +1000 Subject: [PATCH 2/2] Include versionchanged note --- Doc/library/functions.rst | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Doc/library/functions.rst b/Doc/library/functions.rst index d58e4099620445..5b611d639ea718 100644 --- a/Doc/library/functions.rst +++ b/Doc/library/functions.rst @@ -1069,6 +1069,15 @@ are always available. They are listed here in alphabetical order. cell references does *not* affect the contents of previously returned dictionaries. + .. versionchanged:: 3.13 + In previous versions, the semantics of mutating the mapping object + returned from this function were formally undefined. In CPython + specifically, the mapping returned at function scope could be + implicitly refreshed by other operations, such as calling ``locals()`` + again. Obtaining the legacy CPython behaviour now requires explicit + calls to update the initially returned dictionary with the results + of subsequent calls to ``locals()``. + .. function:: map(function, iterable, *iterables)