A Python comprehension binds its loop variable in an inner scope rather than exporting it to the surrounding one.
Python interview: a comprehension has its own loop-variable scope
Operation contract
The first list comprehension builds receipt labels, leaving the surrounding index name unbound. A second builds callbacks that close over the same comprehension variable cell, so all callbacks read its final value when invoked. A default parameter captures each current integer instead. Scope isolation and late binding are separate rules; knowing one does not fix the other.
Failure and ownership boundary
The callbacks here retain only small integers. Capturing a mutable receipt object would retain its reference, not freeze its state. Python scope: local assignment, nonlocal state and late binding, Python closures: capture loop values at the intended time and Python comprehensions: build results without changing the input show the adjacent cases.
Working program
labels = [f"R{index}" for index in range(3)]
late = [lambda: index for index in range(3)]
bound = [lambda index=index: index for index in range(3)]
print(labels)
print("leaked:", "index" in globals())
print("late:", [callback() for callback in late])
print("bound:", [callback() for callback in bound])Output
['R0', 'R1', 'R2']
leaked: False
late: [2, 2, 2]
bound: [0, 1, 2]Costs and limits
Constructing n callbacks and labels costs O(n) time and retained objects. Closing over a single loop cell avoids copying values but creates the late-read behavior; default binding stores one value reference per function.
Common Mistakes
- Comprehension scope isolation does not imply per-iteration closure capture.
- A bound default holds a reference, not a deep copy.
Connected lessons
Python scope: local assignment, nonlocal state and late binding, Python closures: capture loop values at the intended time, Python comprehensions: build results without changing the input.
