[Python-ideas] A comprehension scope issue in PEP 572

Tim Peters tim.peters at gmail.com
Sat May 12 04:56:53 EDT 2018


[Tim]
> ...
> But an assignment expression target name always has the
> same scope within a comprehension.  [which is a consequence
> of the rules - not a rule of its own]

Something related to ponder:  what's the meaning of the following
_without_ the proposed scope change?  So the Golden Binding Rule (GBR)
applies then:

    GBR:  binding a name by any means always makes the name
    local to the block the binding appears in, unless the name is
    declared "global" or "nonlocal" in the block.

def f():
    ys =  [y for _ in range(y := 5)]

The second instance of `y` is local - but local to what?  Since the
range is evaluated _in_ f's scope, presumably that instance of `y` is
local to `f`.  What about the first instance of `y`?  Is that _not_
local to the comprehension despite that the GBR insists it must be
local to the comprehension?

Or does it raise UnboundLocalError for consistency with the GBR, and
"well, so just don't use any name in a comprehension that appears as
an assignment expression target in the expression defining the
iterable for the outermost `for` ".

Or is it that despite that `range(y := 5)` is executed in f's scope,
the _binding_ is actually performed in the comprehension's scope to a
comprehension-local `y`, to both preserve GBR and avoid the
UnboundLocalError? .  But then what if `print(y)` is added after?  If
`range(y := 5)` really was executed in f's scope, surely that must
print 5.

Then what about

    [y for y in range(y := 5)]

?  Now that there's another binding inside the comprehension
establishing that `y` is local to the comprehension "for real", does
that work fine and the rule changes to

    well, so just don't use any name in a comprehension
    that appears as an assignment expression target in the
    expression E defining the iterable for the outermost `for`
    - unless the name is _also_ used in a binding context
    in the comprehension outside of E too

?  Or is that a compile-time error despite that the first 2 y's are
now obviously comprehension-local and the final y obviously f-local?

Or are assignment expressions disallowed in the expression defining
the iterable for the outermost `for`, and both examples are
compile-time errors?

Talk about incoherent ;-)

Under the proposed change,  all instances of `y` are local to `f` in
the first example, and the second example is a compile-time error for
a _coherent_ reason (the ":=" binding implies "not local" for `y` -
which has nothing to do with that it's in the outermost `for` -, but
the "for y in" binding implies "local" for `y`).


More information about the Python-ideas mailing list