0

I cannot see any relevant difference between the for version and the manual one, given the different outcomes:

# MANUAL version ==============================
lst = [lambda: 2]
lst.append(lambda: 2 * lst[0]())
lst.append(lambda: 2 * lst[1]())
lst.append(lambda: 2 * lst[2]())

print([item.__name__ for item in lst])
# ['<lambda>', '<lambda>', '<lambda>', '<lambda>']

print("result:", lst[-1]())
# result: 16

# FOR version ==============================
lst = [lambda: 2]
for i in range(3):
    print(i)
    lst.append(lambda: 2 * lst[i]())

print([item.__name__ for item in lst])
# ['<lambda>', '<lambda>', '<lambda>', '<lambda>']

print("result:", lst[-1]())
# 0
# 1
# 2
# RecursionError: maximum recursion depth exceeded
dawid
  • 663
  • 6
  • 12

2 Answers2

1

The problem here is the i variable. You need bind the variable for each lambda. You can do so with the following syntax: lambda bound_i=i: 2 * lst[bound_i]()

With this, I get the desired outcome. result: 16

I also found this question similar to yours : Python Lambda in a loop. It's a lot more in depth than my answer so it might be worth a read.

Zykerd
  • 138
  • 5
  • I am accepting this as a more direct solution, but @Luke Woodward one is better written. The link is also useful. – dawid Oct 12 '20 at 22:07
1

In the line

    lst.append(lambda: 2 * lst[i]())

the lambdas 'capture', or close over, the variables lst and i, not their values.

At the end of the loop, i has the value 2, and all elements in lst apart from the first are lambdas that return 2 * lst[2](), including lst[2]. So, evaluating lst[2]() requires you to evaluate lst[2](), which requires you to evaluate lst[2](), and so on.

The fix is to create the lambdas inside a function:

def makeLambda(i):
    return lambda: 2 * lst[i]()

lst = [lambda: 2]
for i in range(3):
    print(i)
    lst.append(makeLambda(i))

The reason this works is that each call into makeLambda creates a new scope, with new local variables for each lambda to close over. The value of i within each separate function call doesn't change, and hence this produces the result you expect.

Luke Woodward
  • 63,336
  • 16
  • 89
  • 104