Phase 4 of 25 · Topic 4.4

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.