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 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
--
Regards,
Ivan
_______________________________________________
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe:
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com