Incorrect scope of list comprehension variables
Steven D'Aprano
steve at REMOVE-THIS-cybersource.com.au
Sat Apr 3 08:43:37 EDT 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