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

Ivan Pozdeev vano at mail.mipt.ru
Wed Jun 27 19:57:26 EDT 2018

On 28.06.2018 2:45, Ivan Pozdeev via Python-Dev wrote:
> On 28.06.2018 2:31, Ivan Pozdeev via Python-Dev wrote:
>> On 28.06.2018 1:42, Steven D'Aprano wrote:
>>> On Wed, Jun 27, 2018 at 05:52:16PM +0300, Ivan Pozdeev via 
>>> Python-Dev wrote:
>>>>> What this means in practice is that assignments will go to different
>>>>> scopes depending on *where* they are in the comprehension:
>>>>>      [ expr   for x in iter1  for y in iter2  if cond ...]
>>>>>      [ BBBBBB for x in AAAAAA for y in BBBBBB if BBBBBB ...]
>>>>> Assignments in the section marked "AAAAAA" will be in the local 
>>>>> scope;
>>>>> assignments in the BBBBBB sections will be in the sublocal scope. 
>>>>> That's
>>>>> not too bad, up to the point you try to assign to the same name in
>>>>> AAAAAA and BBBBBB. And then you are likely to get confusing hard to
>>>>> debug UnboundLocalErrors.
>>>> This isn't as messy as you make it sound if you remember that the
>>>> outermost iterable is evaluated only once at the start and all the
>>>> others -- each iteration.
>>> The question isn't *how often* they are evaluated, or how many loops 
>>> you
>>> have, but *what scope* they are evaluated in. Even in a single loop
>>> comprehension, parts of it are evaluated in the local scope and parts
>>> are evaluated in an implicit sublocal scope.
>> All expressions inside the comprehension other than the initial 
>> iterable have access to the loop variables generated by the previous 
>> parts. So they are necessarily evaluated in the internal scope for 
>> that to be possible.
>> Since this is too an essential semantics that one has to know to use 
>> the construct sensibly, I kinda assumed you could make that 
>> connection...
>> E.g.:
>> [(x*y) for x in range(5) if x%2 for y in range(x,5) if not (x+y)%2]
>>    A              B          C              D               E
>> C and D have access to the current x; E and A to both x and y.
> This means btw that users cannot rely on there being a single internal 
> scope, or a scope at all.
> The public guarantee is only the access to the loop variables (and, 
> with the PEP, additional variables from assignments), of the current 
> iteration, generated by the previous parts.
The expressions in the comprehension just somehow automagically 
determine which of the variables are internal and which are local. How 
they do that is an implementation detail.
And the PEP doesn't need to (and probably shouldn't) make guarantees 
here other than where the variables from expressions are promised to be 

>>> The overlap between the two is the trap, if you try to assign to the
>>> same variable in the loop header and then update it in the loop body.
>>> Not to mention the inconsistency that some assignments are accessible
>>> from the surrounding code:
>>>      [expr for a in (x := func(), ...) ]
>>>      print(x)  # works
>>> while the most useful ones, those in the body, will be locked up in an
>>> implicit sublocal scope where they are unreachable from outside of the
>>> comprehension:
>>>      [x := something ...  for a in sequence ]
>>>      print(x)  # fails


More information about the Python-Dev mailing list