<div dir="ltr"><div class="gmail_quote"><div dir="ltr">[Chris Barker]</div>>>> So what about:<br>>>><br>>>> l = [x:=i for i in range(3)]<br>>>><br>>>> vs<br>>>><br>>>> g = (x:=i for i in range(3))<br>>>><br>>>> Is there any way to keep these consistent if the "x" is in the regular local scope?<br><br>[Tim]</div><div class="gmail_quote">>> I'm not clear on what the question is.  The list comprehension would</div><div class="gmail_quote">>> bind ` l ` to [0, 1, 2] and leave the local `x` bound to 2.  The second<br>>> example binds `g` to a generator object, which just sits there<br>>> unexecuted.  That has nothing to do with the PEP, though.<br>>><br>>> If you go on to do, e.g.,<br>>><br>>> l = list(g)<br>>><br>>> then, same as the listcomp, `l` will be bound to [0, 1, 2] and the local `x` will</div><div class="gmail_quote">>> be left bound to 2.<br><br>[Chris]</div><div class="gmail_quote">> OK, it has been said that the priority is that<br>><br>> list(a_gen_expression)<br>><br>> Behave the same as<br>><br>> [the_same_expression]<br><br>That's certainly desirable.</div><div class="gmail_quote"><br><br>> So we’re good there. And maybe it’s  correct that leaving the running<br>> of the gen_exp ‘till later is pretty uncommon, particularly for newbies,<br><br>Common or not, I have no idea why anyone would write a genexp like the one you gave, except to contrive an example of silly behavior exhibited by silly code ;-)<br><br>It's really not interesting to me to make up code as goofy as you can conceive of - the interesting questions are about plausible code (including plausible coding errors).<br><br></div><div class="gmail_quote">>  but:<br>><br>> If the execution of the gen_exp is put off, it really confuses things<br>> — that name being changed would happen at some arbitrary tone, and at<br>> least in theory, the gen_exp could be passed off to somewhere else in<br>> the code, and be run or not run completely remotely from where the<br>> name is used.<br><br>Sure.<br><br>> So while this is technically the same as the comprehension, it is not<br>> the same as a generator function which does get its own scope.</div><div class="gmail_quote"><br></div><div class="gmail_quote">It is the same as a generator function with appropriate scope declarations - a generator expression is, after all, implemented _by_ a nested generator function.  You can write a workalike to your code above today, but nobody worries about that because nobody does that ;-)</div><div class="gmail_quote"><br></div><div class="gmail_quote"><div class="gmail_quote">    def f():</div><div class="gmail_quote">        def bashx(outermost):</div><div class="gmail_quote">            nonlocal x</div><div class="gmail_quote">            for i in outermost:</div><div class="gmail_quote">                x = i</div><div class="gmail_quote">                yield i</div><div class="gmail_quote"><br></div><div class="gmail_quote">        x = 12</div><div class="gmail_quote">        g = bashx(range(3))</div><div class="gmail_quote">        print("x before", x)</div><div class="gmail_quote">        L = list(g)</div><div class="gmail_quote">        print("L", L)</div><div class="gmail_quote">        print("x after", x)</div><div><br>Then calling `f()` prints:</div><div><br></div></div>    x before 12<br>    L [0, 1, 2]<br><div class="gmail_quote"><div><div>    x after 2</div></div></div><div class="gmail_quote"><div><br></div>> And we should be clear how it will work — after all, in py2, the<br>> handling of the looping name was handled differently in gen_exp vs<br>> comprehensions.<br><br>The PEP specifies the semantics.  If it's accepted, that will be folded into the docs.</div><div class="gmail_quote"><br>> So I think a local scope for all comprehension-like things would be</div><div class="gmail_quote">> the way to go.</div><div class="gmail_quote">><br>> But getting back to the original thread topic — python has a number of<br>> places that you can only use expressions — adding the ability to bind<br>> a name in all these places complicates the language significantly.</div><div class="gmail_quote"><br></div><div class="gmail_quote">Did adding ternary `if` (truepart if expression else falsepart) complicate the language significantly?  Python has rarely expanded the number of expression forms, but whenever it has the sky didn't actually fall despite earnest warnings that disaster was inevitable ;-)</div><div class="gmail_quote"><br>>>   Put a body B in a listcomp and any side effects due to executing B<br><br>> Maybe it’s just me, but re-binding a name seems like a whole new<br>> category of side effect.<br><br>With no trickery at all, you've always been able to rebind attributes, and mutate containers, in comprehensions and genexps.  Because `for` targets aren't limited to plain names; e.g.,</div><div class="gmail_quote"><br></div><div class="gmail_quote">    g = (x+y for object.attribute, a[i][j] in zip(range(3), range(3)))<br><br>is already "legal", and will stomp all over the complex `for` targets when executed - there's nothing "local" about them.  But nobody worries about that because nobody does stuff like that.<br><br>And as in my goofy code above, mucking with binding of plain names is also possible today.  Indeed, straightforward if that's what you _want_ to do.  But nobody does.<br><br>It's just not one of Python's goals to make it impossible to write useless code ;-)<br><br></div></div>