Loops & Iteration Protocols
Master iteration mechanics, scope leakage, mutation traps, nested control flow, and generator exhaustion.
Theoretical Mechanics & Memory Architecture
In CPython, iteration is governed by the iterator protocol (dunder iter and dunder next methods) rather than sequential array index pointer arithmetic. When executing a for-loop, CPython emits the GET_ITER opcode to acquire an iterator object, then continually evaluates the FOR_ITER bytecode instruction to push sequential items onto the value stack until a StopIteration signal terminates the block. Understanding generator exhaustion, loop target variable scope leakage into the outer frame, and internal offset mechanics is essential for writing deterministic control flow in technical interviews.
Sequence iterators in CPython retain an internal integer offset pointer (it_index). On each iteration, FOR_ITER inspects the underlying sequence, fetches the element at it_index, and increments it_index by one. If items are deleted or inserted into the sequence during iteration, the memory addresses shift immediately while it_index continues incrementing monotonically, causing CPython to silently skip or duplicate elements.
Modifying a list in place while looping over it (for example, invoking lst.remove(item) inside the loop) alters element indices mid-traversal. If index 0 is deleted, the item at index 1 shifts into index 0, but CPython's internal iterator advances to index 1 next, skipping the newly shifted item completely. To avoid this trap, iterate over a shallow slice copy (for item in lst[:]:) or build a filtered list with a list comprehension.
Interactive Dry-Run Execution Workspace
Modifying List While Iterating
Trace CPython execution step-by-step and deduce the exact stdout string emitted by this snippet.
lst = [1, 2, 2, 3]
for x in lst:
if x == 2:
lst.remove(x)
print(lst)Frequently Asked Questions on Loops & Iteration Protocols
Why does deleting items from a list inside a for-loop skip elements in Python?
CPython sequence iterators maintain an internal integer counter that increments on every step. When you remove an item, all subsequent elements shift left by one position. On the next step, the counter advances to the next index, skipping over the element that just shifted into the current index slot. Always iterate over a copy or use list comprehensions.
How do for-loop target variables behave regarding scope in Python?
Python loops do not introduce a new local scope. The loop variable leaks into the surrounding function or module namespace and retains the value from the loop's final iteration. If the iterable is empty, the variable is never assigned.
What is the concrete difference between an Iterable and an Iterator in CPython?
An Iterable is any object implementing __iter__() that produces a fresh iterator (such as lists, tuples, or dicts). An Iterator implements both __iter__() (returning itself) and __next__(), maintaining an active cursor and raising StopIteration when exhausted. Iterators are single-pass streams.