def makeActions():
acts=[]
for i in range(5):
print len(acts)
acts.append(lambda x: i ** x)
print acts[i]
return acts
acts=makeActions()
for i in range(5):
print acts[i](2)
Output:
16
16
16
16
16
Expected output:
0
1
4
9
16
Because the i
in the lambda is probably not what you expect. To verify this, change the code:
acts.append(lambda x: (i, i ** x))
Now the print
tells you the value of i
:
(4, 16)
(4, 16)
(4, 16)
(4, 16)
(4, 16)
This means that the lambda
doesn't copy the value of i
but keeps a reference to the variable, so all lambda
s see the same value. To fix this, copy i
:
acts.append(lambda x, i=i: (i, i ** x))
The little i=i
creates a local copy of i
inside the lambda
.
[EDIT] Now why is this? In the versions of Python before 2.1, local functions (i.e. functions defined inside of other functions) couldn't see the variables in the same scope.
def makeActions():
acts=[]
for i in range(5):
print len(acts)
def f(x): # <-- Define local function
return i ** x
acts.append(f)
print acts[i]
return acts
then you'd get an error that i
isn't defined. lambda
could see the enclosing scope at the cost of a somewhat wierd syntax.
This behavior has been fixed in one of the recent versions of Python (2.5, IIRC). With these old versions of Python, you'd have to write:
def f(x, i=i): # <-- Must copy i
return i ** x
Since the fix (see PEP 3104), f()
can see variables in the same scope, so lambda
isn't necessary anymore.
Because all lambda functions you create are bound to i, which becomes 4 at the end of loop, and as we all well know 4*4 = 16
to avoid that create your functions using nested function(closure) e.g.
def makePowerFunc(base):
def powerFunc(x):
return base**x
return powerFunc
def makeActions():
acts=[]
for i in range(5):
acts.append(makePowerFunc(i))
return acts
acts=makeActions()
for i in range(5):
print acts[i](2)
output:
0
1
4
9
16
There are other ways to solve it, but it is better to have a named nested function instead of lambda, and you can do many more things with such closures
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With