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