What does this print: a list of lambdas created in a loop, each returning i?
All the lambdas print the last value of i. Closures capture the variable, not its value at creation time, and i is looked up when the lambda is called. Fix it with a default argument: lambda i=i: i.
Explain it simply
Five students are told, "write down whatever number is on the board when I ask." The board changes from 0 to 4 while they wait. When finally asked, every student reads the board and writes 4. They did not memorise the number, they only remembered where to look.
Example
funcs = [lambda: i for i in range(3)]
print([f() for f in funcs]) # Output: [2, 2, 2]
fixed = [lambda i=i: i for i in range(3)]
print([f() for f in fixed]) # Output: [0, 1, 2]
from functools import partial
def show(i):
return i
bound = [partial(show, i) for i in range(3)]
print([f() for f in bound]) # Output: [0, 1, 2]The first list prints [2, 2, 2] because all three lambdas share one i, and by the time they run the loop has finished with i = 2. A default argument is evaluated immediately, so each lambda gets its own copy.
What to say in the interview
"Closures capture variables, not values. The lambdas all look up i at call time, after the loop ends, so they see its final value. I fix it by binding the current value with a default argument, functools.partial, or a factory function that takes i as a parameter."