Late binding in closures
Closures in Python capture variables, not their values at the moment the inner function is created. This surprises many people in loops, where several functions end up using the same final value.
What is happening?
This pattern looks like it should work:
functions = []
for i in range(3):
functions.append(lambda: i)
print([func() for func in functions])
Output:
[2, 2, 2]
What you might expect: Each function remembers its own loop value.
What actually happens: Each function looks up i later, after the loop has finished.
Why this surprises people
The inner function closes over the variable name i, not a frozen copy of its value. By the time the functions run, the loop is done and i contains its last value.
This is called late binding.
Prefer this instead
One common fix is to bind the current value as a default argument:
functions = []
for i in range(3):
functions.append(lambda i=i: i)
print([func() for func in functions])
Output:
[0, 1, 2]
Now each lambda gets its own value.
You can also use a regular helper function when that reads more clearly.
Rules of thumb
- Be careful with closures created inside loops.
- Remember that closures capture variables, not snapshot values.
- Use a default argument such as
lambda i=i: iwhen you need the current loop value. - Prefer a small named function when the lambda workaround feels cryptic.