7

I struggle with making lambdas work. The code here is example, but it shows my problem well.

lambdas = list()

for i in range(5):
    lambdas.append(lambda x:i*i*x)


print lambdas[0](1)
print lambdas[2](1)

This give me 16, but I expect to have different value for different lambda. Why is happening!

batchtest
  • 85
  • 3
  • "Scoping in Python is lexical. A closure will always remember the name and scope of the variable, not the object it's pointing to." http://stackoverflow.com/questions/2295290/what-do-lambda-function-closures-capture-in-python Your lambda captures the name `i`, not the *object value* referenced by `i`. – Shashank Mar 25 '15 at 01:04

2 Answers2

9

In this code:

for i in range(5):
    lambdas.append(lambda x:i*i*x)

The value of i is determined when the function is run. The value of i when the function is defined is lost.

Use instead:

lambdas = list()

for i in range(5):
    lambdas.append(lambda x, i=i : i*i*x)  

print lambdas[0](1)
print lambdas[2](1)

This produces:

0
4

This works because, as a special case, the default arguments to a function, as in i=i above, bind immediately.

John1024
  • 109,961
  • 14
  • 137
  • 171
6

i is 4 when your loop ends so i is 4 for every lambda.

If you print i outside the loop you will see it is 4:

for i in range(5):
    lambdas.append(lambda x: i * i * x)

print(i)
4

You are using a variable that is being updated throughout the loop, if you call the lambda inside the loop you would get what you were expecting.

for i in range(5):
    lambdas.append(lambda x: i * i * x)
    print(lambda x: i * i * x)(1)
0
1
4
9
16

The behaviour is what you would expect, i is simply a variable like any other.

On a side note you could use a list comp to create your list:

lambdas = [lambda x,i=i: i * i * x for i in xrange(5)]
Padraic Cunningham
  • 176,452
  • 29
  • 245
  • 321