Incorrect scope of list comprehension variables

Steven D'Aprano steve at REMOVE-THIS-cybersource.com.au
Sat Apr 3 14:43:37 CEST 2010


On Sat, 03 Apr 2010 12:30:32 +0200, Alain Ketterlin wrote:

> Hi all,
> 
> I've just spent a few hours debugging code similar to this:
> 
> d = dict()
> for r in [1,2,3]:
>     d[r] = [r for r in [4,5,6]]
> print d

This isn't directly relevant to your problem, but why use a list 
comprehension in the first place? [r for r in [4,5,6]] is just [4,5,6], 
only slower.

I presume that is just a stand-in for a more useful list comp, but I 
mention it because I have seen people do exactly that, in real code, 
without knowing any better. (I may have even done so myself, once or 
twice.)


> THe problem is that the "r" in d[r] somehow captures the value of the
> "r" in the list comprehension, and somehow kills the loop interator. The
> (unexpected) result is {6: [4, 5, 6]}.

Actually, no it doesn't kill the loop at all. You have misinterpreted 
what you have seen:

>>> d = dict()
>>> for r in [1,2,3]:
...     print r
...     d[r] = [r for r in [4,5,6]]
...     print d
...
1
{6: [4, 5, 6]}
2
{6: [4, 5, 6]}
3
{6: [4, 5, 6]}

 

> Changing r to s inside the list
> leads to the correct (imo) result.
> 
> Is this expected? Is this a known problem? Is it solved in newer
> versions?

Yes, yes and yes.

It is expected, because list comprehensions leak the variable into the 
enclosing scope. Yes, it is a problem, as you have found, although 
frankly it is easy enough to make sure your list comp variable has a 
unique name. And yes, it is fixed in Python 3.1.



-- 
Steven



More information about the Python-list mailing list