<div dir="ltr"><div><div>I am convinced by Tim's motivation. I hadn't thought of this use case before -- I had mostly thought "local scope in a comprehension or generator expression is the locals of the synthetic function". But Tim's reasoning feels right.<br><br>The only solution that makes sense to me is Steven's (2). (1) is what the PEP currently says and what Tim doesn't want; (3) has no precedent (function defaults don't really work like this) and just gets my hackles all up. (I can't even tell if Steven meant it as a serious proposal.)<br><br>So let's see if we can change PEP 572 so that := inside a comprehension or generator expression al ways assigns to a variable in the containing scope.<br><br>It may be inconsistent with the scope of the loop control variable, but it's consistent with uses of := outside comprehensions:<br><br></div> [x := 0]<br> [x := i for i in range(1)]<br><br></div><div>both have the side effect of setting x to zero. I like that.<br><br></div><div>There's one corner case (again) -- class scopes. If the containing scope is a function, everything's fine, we can use the existing closure machinery. If the containing scope is global, everything's fine too, we can treat it as a global. But if the containing scope is a class, we can't easily extend the current machinery. But this breakage is similar to the existing breakage with comprehensions in class scope that reference class variables:<br><br></div><div> class C:<br></div><div> hosts = ['boring', 'haring', 'tering']<br></div><div> full_hosts = [host + suffix for suffix in ('.<a href="http://cwi.nl">cwi.nl</a>', '.com') for host in hosts]<br clear="all"></div><div><div><div><div class="gmail_extra"><br>Traceback (most recent call last):<br> File "<stdin>", line 1, in <module><br> File "<stdin>", line 3, in C<br> File "<stdin>", line 3, in <listcomp><br>NameError: name 'hosts' is not defined<br><br></div><div class="gmail_extra">I propose to punt on this case. If we want to fix it we can fix it in a number of ways and the fix can easily apply to both getting and setting -- but this is a separate fix (and we should take it out of PEP 572).<br><br></div><div class="gmail_extra">PS1. The various proposals that add random extra keywords to the syntax (like 'for nonlocal i') don't appeal to me at all.<br><br></div><div class="gmail_extra">PS2. IIRC the reason we gave loop control variables their own scope was the poor imagination of many people when it comes to choosing loop control variable names. We had seen just too many examples of<br><br></div><div class="gmail_extra"> for x in something:<br></div><div class="gmail_extra"> ...lots of code using x...<br></div><div class="gmail_extra"> blah blah [x+1 for x in something else]<br></div><div class="gmail_extra"> ...some more code using x, broken...<br></div><div class="gmail_extra"><br></div><div class="gmail_extra">It's true that this can also happen with a for-loop statement nested inside the outer loop (and it does) but the case of a comprehension was easier to miss. I've never looked back.<br><br></div><div class="gmail_extra">PS3. Comprehensions and generator expressions should be interchangeable. They just look too similar to have different semantics (and the possibly delayed execution of generator expressions is not an issue -- it's rare, and closure semantics make it work just fine).<br></div><div class="gmail_extra"><br></div><div class="gmail_extra">-- <br><div class="gmail_signature">--Guido van Rossum (<a href="http://python.org/~guido" target="_blank">python.org/~guido</a>)</div>
</div></div></div></div></div>