Odd name shadowing in comprehension

Steve D'Aprano steve+python at pearwood.info
Sat Oct 22 22:42:13 EDT 2016


On Sun, 23 Oct 2016 10:57 am, 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)]

That surprises me too. I wouldn't have expected that y is both global and
local to the comprehension at the same time.

I think that this is a bug in list comprehensions and should at least give a
warning that y is being used as both local and non-local.


This is what happens if you try to access a local before it exists:

py> [(y, x) for x in (1, y) for y in (10, 20)]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'y' is not defined


Swap the order, and it works:

py> [(y, x) for y in (10, 20) for x in (1, y)]
[(10, 1), (10, 10), (20, 1), (20, 20)]


But if y happens to exist as a global, the first version mysteriously works!

py> y = 999
py> [(y, x) for x in (1, y) for y in (10, 20)]
[(10, 1), (20, 1), (10, 999), (20, 999)]


Let's expand the list comp to a function:

y = 999
def list_comp():
    result = []
    for x in (1, y):
        for y in (10, 20):
            result.append((y, x))
    return result


Calling that function gives a NameError, specifically:

UnboundLocalError: local variable 'y' referenced before assignment


> Normally, a comprehension is described as being equivalent to an
> unrolled loop, inside a nested function. 

I don't think that's quite the right description, but something like that.

> 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()

Indeed.




-- 
Steve
“Cheer up,” they said, “things could be worse.” So I cheered up, and sure
enough, things got worse.




More information about the Python-list mailing list