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

Tim Peters tim.peters at gmail.com
Tue May 8 12:18:16 EDT 2018

>> (inside a synthetic function created to
>> implement a listcomp/genexp, names bound by "=" are local; names bound
>> by ":=" are nonlocal; names bound by both are "who cares?"-
>> compiler-time error would be fine by me, or the first person to show a
>> real use case wins).

[Jacco van Dorp <j.van.dorp at deonet.nl>]
> Wait, you can't use = in a listcomp, right ? Or are you talking about
> the implementation hidden to the casual user ?

Sorry, I was too obscure there - I intended "=" to mean "name binding
by any means other than :=".  Off the top of my head, I believe that -
today - the only "any means other than :=" possible in a
listcomp/genexp is appearing as a target in a `for` clause (like the
`i` in "[i+1 for i in iterable]`).  If there's some other way I
missed, I meant to cover that too.

But, yes, you're right, `names bound by "="` makes no literal sense at
all there.

> I thought letting := bind to the surrounding scope was fine basically
> because it's currently not possible, so therefore there would be no
> syntactic ambiguity, and it'd actually do what people would expect.

It's not really about the semantics of `:=` so much as about how
synthetic functions are defined.  In most cases, it amounts to saying
"in the nested function synthesized for a listcomp/genexp, if a name
`x` appears as the target of a binding expression in the body, a
`nonlocal x` declaration is generated near the top of the synthetic

For example, if this block appears inside a function:

    it = (i for i in range(10))
    total = 0
    for psum in (total := total + value for value in it):

under the current PEP meaning it blows up in the same way this code
blows up today:

    it = (i for i in range(10))
    total = 0
    def _func(it):
        for value in it:
          total = total + value  # blows up here
          yield total
    for psum in _func(it):


    UnboundLocalError: local variable 'total' referenced before assignment

But add

        nonlocal total

at the top of `_func()` and it works fine (displays 0, 1, 3, 6, 10, 15, ...).

So it's not really about what ":=" does, but about how ":=" affects
scope in synthesized nested functions.

But if you wrote a nested function yourself?  There's no suggestion
here that ":=" have any effect on scope decisions in explicitly given
nested functions (same as for "=", it would imply "the target is
local"), just on those generated "by magic" for listcomps/genexps.

Maybe there should be, though.  My initial thought was "no, because
the user has total control over scope decisions in explicitly given
functions today, but if something was magically made nonlocal they
would have no way to override that".

More information about the Python-ideas mailing list