<div dir="ltr"><div class="gmail_quote"><div dir="ltr">[Guido]<br>> A quick follow-up: PEP 572 currently has two ideas: (a) introduce := for inline<br>> assignment, (b) when := is used in a comprehension, set the scope for the<br>> target as if the assignment occurred outside any comprehensions. It seems<br>> we have more support for (a) than for (b) -- at least Nick and Greg seem to<br>> be +0 or better for (a) but -1 for (b). IIRC (b) originated with Tim. But his<br>> essay on the topic, included as Appendix A<br>> (<a href="https://www.python.org/dev/peps/pep-0572/#appendix-a-tim-peters-s-findings" target="_blank">https://www.python.org/dev/peps/pep-0572/#appendix-a-tim-peters-s-findings</a>)<br>> does not even mention comprehensions.<br><br>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).<br><br><br></div><div dir="ltr">:> However, he did post his motivation for (b) on python-ideas, IIRC a bit<br>> before PyCon; and the main text of the PEP gives a strong motivation<br>> (<a href="https://www.python.org/dev/peps/pep-0572/#scope-of-the-target" target="_blank">https://www.python.org/dev/peps/pep-0572/#scope-of-the-target</a>). Nevertheless,<br>> maybe we should compromise and drop (b)?<br></div><div><br>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)<br><br>p = None # to establish the intended scope of `p`<br>while any(<nonlocal p>  # split across lines just for readability</div><div>                n % p == 0 for p in small_primes):<br>    n //= p<br><br>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.<br><br>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:<br><div><br></div><div>def f():</div><div>    y = -1</div><div>    ys = [y for _ in range(y := 5)]</div><div>    print(y, ys)</div><div><br></div><div>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.</div><div><br></div><div>def g():</div><div>    y = -1</div><div>    ys = [y for y in range(y := 5)]</div><div>    print(y, ys)</div><div><br></div><div>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.</div><div><br></div><div>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.</div></div><div><br></div></div></div>