[Python-Dev] Informal educator feedback on PEP 572 (was Re: 2018 Python Language Summit coverage, last part)

Paul Moore p.f.moore at gmail.com
Mon Jun 25 08:25:09 EDT 2018

On 25 June 2018 at 12:44, Nick Coghlan <ncoghlan at gmail.com> wrote:
> Unfortunately, I think the key rationale for (b) is that if you
> *don't* do something along those lines, then there's a different
> strange scoping discrepancy that arises between the non-comprehension
> forms of container displays and the comprehension forms:

I've been mostly ignoring this proposal for a while now, so I'm going
to respond here in the context of someone with a bit of an idea of the
underlying complexities, but otherwise coming at it as a new proposal.

>     (NAME := EXPR,) # Binds a local
>     tuple(NAME := EXPR for __ in range(1)) # Doesn't bind a local
>     [NAME := EXPR] # Binds a local
>     [NAME := EXPR for __ in range(1)] # Doesn't bind a local
>     list(NAME := EXPR for __ in range(1)) # Doesn't bind a local
>     {NAME := EXPR} # Binds a local
>     {NAME := EXPR for __ in range(1)} # Doesn't bind a local
>     set(NAME := EXPR for __ in range(1)) # Doesn't bind a local
>     {NAME := EXPR : EXPR2} # Binds a local
>     {NAME := EXPR : EXPR2 for __ in range(1)} # Doesn't bind a local
>     set((NAME := EXPR, EXPR2) for __ in range(1)) # Doesn't bind a local

None of those "discrepancies" bother me in the slightest, when taken
in isolation as you present them here. I suspect you could lead me
through a chain of logic that left me understanding why you describe
them as discrepancies, but without that explanation, I'm fine with all
of them.

I'd also say that they seem contrived (not just in the use of
artificial names, but also in the sense that I'm not sure why I'd want
to use this *pattern*) so I'd happily say "well, don't do that then"
if things started behaving non-intuitively.

> Those scoping inconsistencies aren't *new*, but provoking them
> currently involves either class scopes, or messing about with
> locals().

And to reinforce my point above, I already consider putting
significant code in class scopes, or using locals() to be techniques
that should only be used sparingly and with a clear understanding of
the subtleties. I'm sure you could say "but the examples above would
be much more common" in response to which I'd like to see real use
cases that behave non-intuitively in the way you're concerned about.

> The one virtue that choosing this particular set of discrepancies has
> is that the explanation for why they happen is the same as the
> explanation for how the iteration variable gets hidden from the
> containing scope: because "(EXPR for ....)" et al create an implicitly
> nested scope, and that nested scope behaves the same way as an
> explicitly nested scope as far as name binding and name resolution is
> concerned.

But that's precisely why I find the behaviour intuitive - the nested
scope is the *reason* things behave this way, not some sort of
easily-overlooked way the "problem" can be explained away.

> Parent local scoping tries to mitigate the surface inconsistency by
> changing how write semantics are defined for implicitly nested scopes,
> but that comes at the cost of making those semantics inconsistent with
> explicitly nested scopes and with the read semantics of implicitly
> nested scopes.
> The early iterations of PEP 572 tried to duck this whole realm of
> potential semantic inconsistencies by introducing sublocal scoping
> instead, such that the scoping for assignment expression targets would
> be unusual, but they'd be consistently unusual regardless of where
> they appeared, and their quirks would clearly be the result of how
> assignment expressions were defined, rather than only showing up in
> how they interacted with other scoping design decisions made years
> ago.

Those last two paragraphs made my head explode, as far as I can see by
virtue of the fact that they try to over-analyze the fairly simple
intuition I have that "there's a nested scope involved".

Disclaimer: I may well have got a *lot* of subtleties wrong here, and
it's quite likely that my impressions don't stand up to the harsh
reality of how the implementation works. But my comments are on the
basis of my *intuition*, whether that's right or wrong. And if the
reality violates my intuition, it's *other* constructs that I find
non-intuitive, not this one. (I'm perfectly happy to concede that it's
not possible to avoid *any* non-intuitive behaviour - all I'm trying
to say is that my intuition doesn't balk at this one, unlike yours).


More information about the Python-Dev mailing list