[Python-Dev] [PEP 558] thinking through locals() semantics
On Tue, 28 May 2019 at 06:00, Nathaniel Smith <njs at pobox.com> wrote:
> - 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().
If I understand you, this "justified" action at a distance is exactly
similar to how os.environ works, making it very reasonable that locals
and globals work the same (indeed, explaining that locals *doesn't* do
this at the moment is why (IMO) people consider locals() as "a bit
> - 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.
Yep, this is the one that most non-experts commenting on this thread
(including me) seem to have been surprised by.
> 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).
This summary leaves me very strongly feeling that I prefer [proxy]
first, then [snapshot], with the two [PEP] variants a distant third
Of course, all of this is only if we have decided to formalise the
semantics and change CPython to conform. I've never personally been
affected by any of the edge cases with locals(), so on a purely
personal basis, I'm equally happy with "do nothing" :-)