Odd name shadowing in comprehension

Terry Reedy tjreedy at udel.edu
Sat Oct 22 20:43:51 EDT 2016


On 10/22/2016 7:57 PM, Chris Angelico wrote:
> This surprised me.
>
> Python 3.4.2 (default, Oct  8 2014, 10:45:20)
> [GCC 4.9.1] on linux
> Type "help", "copyright", "credits" or "license" for more information.
>>>> y=6
>>>> [(x,y) for x in range(y) for y in range(3)]
> [(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (2,
> 2), (3, 0), (3, 1), (3, 2), (4, 0), (4, 1), (4, 2), (5, 0), (5, 1),
> (5, 2)]
>>>> [(x,y) for x in range(3) for z in range(y) for y in range(3)]
> Traceback (most recent call last):
>   File "<stdin>", line 1, in <module>
>   File "<stdin>", line 1, in <listcomp>
> UnboundLocalError: local variable 'y' referenced before assignment
>
> Normally, a comprehension is described as being equivalent to an
> unrolled loop, inside a nested function. That would be like this:
>
> def temp():
>     ret = []
>     for x in range(y):
>         for y in range(3):
>             ret.append((x,y))
>     return ret
> temp()

This would make the first example fail, which would not be nice.


> But it seems that the first iterator (and only that one) is evaluated
> in the parent context:

Because the first iterator *can* always be evaluated.

> def temp(iter):
>     ret = []
>     for x in iter:
>         for y in range(3):
>             ret.append((x, y))
>     return ret
> temp(iter(range(y)))
>
> Why is this? It seems rather curious.

Guido explained this somewhere some time ago.
Not sure it is documented very well.
In general, subordinate clauses depend on the initial loop variable, 
hence cannot be evaluated.


-- 
Terry Jan Reedy




More information about the Python-list mailing list