Why is the following code 16 always displayed?

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 Result:

 0 1 4 9 16 
+4
source share
4 answers

Because i in lambda is probably not what you expect. To check this, change the code:

 acts.append(lambda x: (i, i ** x)) 

Now print tells you the value of i :

 (4, 16) (4, 16) (4, 16) (4, 16) (4, 16) 

This means that lambda does not copy the value of i , but retains a reference to the variable, so all lambda see the same value. To fix this, copy i :

 acts.append(lambda x, i=i: (i, i ** x)) 

Little i=i creates a local copy of i inside lambda .

[EDIT] Now why is this? In versions of Python prior to 2.1, local functions (i.e. functions defined inside other functions) could not see 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 will get error i . lambda could see the covering area due to a somewhat weirder syntax.

This behavior has been fixed in one of the latest versions of Python (2.5, IIRC). Using these old versions of Python you will need to write:

  def f(x, i=i): # <-- Must copy i return i ** x 

Since the fix is ​​(see PEP 3104 ), f() can see variables in the same area, so lambda no longer needed.

+23
source

Since all the lambda functions you created are tied to i, which becomes 4 at the end of the cycle, and as we all know 4 * 4 = 16

to avoid creating your functions with a nested function (closure), for example.

 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) 

exit:

 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

+6
source

This is a contradictory or at least less common syntax. I think you meant:

 acts.append(lambda x, i = i: i ** x) 

which will output:

 0 1 4 9 16 

n. in your version,

 acts.append(lambda x, i: i ** x) 

lambda functions were created, but they all referred to the local i from the loop, which stopped at i = 4 , so all your lambdas said: lambda x: 4 ** x , therefore

 for i in range(5): print acts[i](2) 

will print all 16.


Ffn. broken lambda blog post: http://math.andrej.com/2009/04/09/pythons-lambda-is-broken/

+5
source

This phenomenon is called lambda binding, see What is a lambda binding. in python?

+3
source

All Articles