[Python-Dev] [PEP 558] thinking through locals() semantics

Nathaniel Smith njs at pobox.com
Tue May 28 00:57:34 EDT 2019

On Mon, May 27, 2019 at 9:18 PM Guido van Rossum <guido at python.org> wrote:
> Note that the weird, Action At A Distance behavior is also visible for locals() called at module scope (since there, locals() is globals(), which returns the actual dict that's the module's __dict__, i.e. the Source Of Truth. So I think it's unavoidable in general, and we would do wise not to try and "fix" it just for function locals. (And I certainly don't want to mess with globals().)

I think it's worth distinguishing between two different types of weird
Action At A Distance here:

- There's the "justified" action-at-a-distance that currently happens
at module scope, where locals().__setitem__ affects variable lookup,
and variable mutation affects locals().__getitem__. This can produce
surprising results if you pass locals() into something that's
expecting a regular dict, but it's also arguably the point of an
environment introspection API, and like you say, it's unavoidable and
expected at module scope and when using globals().

- And then there's the "spooky" action-at-a-distance that currently
happens at function scope, where calling locals() has the side-effect
of mutating the return value from previous calls to locals(), and the
objects returned from locals may or may not spontaneously mutate
themselves depending on whether some other code registered a trace
function. This is traditional, but extremely surprising if you aren't
deeply familiar with internals of CPython's implementation.

Of the four designs:

[PEP] and [PEP-minus-tracing] both have "spooky" action-at-a-distance
(worse in [PEP]), but they don't have "justified"

[proxy] adds "justified" action-at-a-distance, and removes "spooky"
action at a distance.

[snapshot] gets rid of both kinds of action-at-a-distance (at least in
function scope).


Nathaniel J. Smith -- https://vorpus.org

More information about the Python-Dev mailing list