Interview frequency: …
Short answer
A closure is an inner function that keeps a reference to variables of the enclosing scope, but the variable's value is read at call time, not creation time, so all functions created in a loop see the loop variable's last value.
Explanation
A closure refers to the variable itself (a cell), not to a copy of its value. When you create lambdas inside a loop and run them later, they all read the final value of the loop variable. Solutions: bind the value as a default parameter (lambda n=n: n), use functools.partial, or use a factory function that creates a new scope for each value. To modify an enclosing variable from the inner function, use nonlocal.
Code example
callbacks = [lambda: n for n in range(3)]
print([f() for f in callbacks]) # [2, 2, 2]
callbacks = [lambda n=n: n for n in range(3)]
print([f() for f in callbacks]) # [0, 1, 2]
def counter():
count = 0
def inc():
nonlocal count
count += 1
return count
return incCommon mistakes
- Creating callbacks inside a loop and expecting each to carry its own value.
- Forgetting nonlocal when modifying an enclosing variable, which raises UnboundLocalError.