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

Tim Peters tim.peters at gmail.com
Sun Jun 24 15:03:07 EDT 2018

> A quick follow-up: PEP 572 currently has two ideas: (a) introduce := for
> assignment, (b) when := is used in a comprehension, set the scope for the
> target as if the assignment occurred outside any comprehensions. It seems
> we have more support for (a) than for (b) -- at least Nick and Greg seem
> be +0 or better for (a) but -1 for (b). IIRC (b) originated with Tim. But
> essay on the topic, included as Appendix A
> (
> does not even mention comprehensions.

I was writing up my observations about simple changes to existing code.
Since there's nothing sanely akin to binding non-for-targets possible in
comprehensions now, comprehensions were out of scope for that effort (which
was limited to staring at existing code already doing bindings).

:> However, he did post his motivation for (b) on python-ideas, IIRC a bit
> before PyCon; and the main text of the PEP gives a strong motivation
> (https://www.python.org/dev/peps/pep-0572/#scope-of-the-target).
> maybe we should compromise and drop (b)?

Two things to say about that.  First, the original example I gave would be
approximately as well addressed by allowing to declare intended scopes in
magically synthesized functions; like (say)

p = None # to establish the intended scope of `p`
while any(<nonlocal p>  # split across lines just for readability
                n % p == 0 for p in small_primes):
    n //= p

It didn't really require an inline assignment, just a way to override the
unwanted (in this case) "all `for` targets are local to the invisible
function" rigid consequence of the implementation du jour.

Second, if it's dropped, then the PEP needs more words to define what
happens in cases like the following, because different textual parts of a
comprehension execute in different scopes, and that can  become visible
when bindings can be embedded:

def f():
    y = -1
    ys = [y for _ in range(y := 5)]
    print(y, ys)

Here `range(y := 5)` is executed in f's scope.  Presumably the `y` in `y
for` also refers to f's scope, despite that `y` textually _appears_ to be
assigned to in the body of the listcomp, and so would - for that reason -
expected to be local to the synthesized function, and so raise
`UnboundLocalError` when referenced.  It's incoherent without detailed
knowledge of the implementation.

def g():
    y = -1
    ys = [y for y in range(y := 5)]
    print(y, ys)

And here the `y` in `y for y` is local to the synthesized function, and
presumably has nothing to do with the `y` in the `range()` call.  That's
incoherent in its own way.

Under the current PEP, all instances of `y` in `f` refer to the f-local
`y`, and the listcomp in `g` is a compile-time error.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-dev/attachments/20180624/f9c907c1/attachment.html>

More information about the Python-Dev mailing list