Closures resolve captured variables when called. Functions created in a loop can therefore observe the loop variable’s final value.
Before you start
You should know Python functions, collections and exceptions. Use a small isolated script or interactive session to trace the example. Pay attention to when objects are created and when work executes; iteration, binding and mutation can happen at different points in a program.
The practical goal is to reason through this situation: Several delayed callbacks can all print the last index. Read the walkthrough first, then try the interview exercise before opening its answer. The important part is explaining the decision and its consequences, rather than remembering a definition alone.
Step-by-step walkthrough
Step 1: Find the captured variable
Loop callbacks can all refer to the same changing variable.
Step 2: Trace delayed execution
After the loop, that variable holds the final iteration’s value.
Step 3: Bind separate values
Use a factory or default argument to capture the intended per-iteration value.
Worked scenario
Several delayed callbacks can all print the last index.
callbacks = [lambda value=i: value for i in range(3)]
print([callback() for callback in callbacks]) # [0, 1, 2]Without the default argument, each callback reads i later and can report the final value. The default is evaluated when each lambda is created.
Common mistake
Assuming the value was copied at function creation misreads closure behavior.
Verify the behavior
Run callbacks after the loop and compare bound and unbound versions, including an empty loop.
Interview exercise
Capture each loop value.
Answer and reasoning
Bind it deliberately through a default argument or a factory that creates a separate local variable.
Continue learning
Compare the scenario with the Python interview questions and test your understanding with the Python MCQs. For terminology and implementation details, consult the reference material.