lambda semantics in for loop

Mark Rowe bdash at gmx.net
Sun Jan 5 07:58:37 EST 2003


On Monday, January 6, 2003, at 01:36 AM, Henk Punt wrote:

> Hi,
>
> When I have the following bit of python code:
>
>>>> l = []
>>>> for i in range(10):
> ...     l.append(lambda x: x + i)
>
> I would expect:
>
> l[0](0) = 0
> l[1](0) = 1
>
> l[0](1) = 1
> l[1](1) = 2
>
> etc.
>
> instead
>
> l[0](0) = 9
> l[1](0) = 9
>
> l[0](1) = 10
> l[1](1) = 10
>
> It seems that the 'i' in the lambda binds to the last value of i in the
> for loop.
> Is this because 'i' is really a pointer and not the value of 'i' 
> itself?.
> Please enlighten me!,
>
> How do I modify the example so that I would get my expected semantics.
> Should I copy 'i' to force the creation of a new object?, If so how 
> would
> this work in the case where i is a string. I've tried to coerce python
> into making a deepcopy of a string so that id(s) != id(copy(s)) but 
> I've
> not been able to do that also.
>
> Thanx already,
>
> Henk Punt.

 From the Python Reference manuals section on Naming on Binding 
(http://www.python.org/doc/current/ref/naming.html):
If a name is bound in a block, it is a local variable of that block. If 
a name is bound at the module level, it is a global variable. (The 
variables of the module code block are local and global.) If a variable 
is used in a code block but not defined there, it is a free variable .

In your case, the variable i is bound at module level and is therefore 
treated as a global variable.  This means that its value when you call 
the lambda functions is used.  To get around this you can make i local 
to the lambda by passing it as a default argument like so:

 >>> l = []
 >>> for i in range(10):
...   l.append(lambda x, i=i: x + i)
...
 >>> l[0](0)
0
 >>> l[1](0)
1
 >>> l[9](0)
9
 >>> l[5](5)
10
 >>>


-- Mark Rowe
bdash at clear.net.nz






More information about the Python-list mailing list