Closures & __closure__ Cell Variables (Late-Binding Loop Trap)
1Concept
A closure retains references to variables from its enclosing scope via `__closure__` cell objects. A notorious trap is Late Binding: functions created inside loops bind to the variable name, not the value at creation time, causing all lambdas to see the loop's final value.
2Architecture Diagram
Late-Binding Trap: funcs = [lambda: i for i in range(3)] ---> All return 2! Default Arg Fix: funcs = [lambda i=i: i for i in range(3)] ---> Returns 0, 1, 2!
3Code Example
Python 3.12
broken_handlers = [lambda: i for i in range(3)]
fixed_handlers = [lambda i=i: i for i in range(3)]
print(f"Broken Lambdas: {[f() for f in broken_handlers]}")
print(f"Fixed Lambdas: {[f() for f in fixed_handlers]}")4Expected Output
Broken Lambdas: [2, 2, 2] Fixed Lambdas: [0, 1, 2]
5Key Takeaways
- ✓Closures store enclosing free variables inside the function's `__closure__` attribute.
- ✓Use default argument binding `arg=val` to freeze loop variables in closures.
- ✓`functools.partial` is another clean alternative to freeze arguments.