Generators & Iterators Protocols
Master yield mechanics, send/throw/close, yield from delegation, PEP 479, iterator protocol edge cases, and advanced itertools patterns.
Theoretical Mechanics & Memory Architecture
Generators in Python are resumable execution coroutines implemented via generator functions (containing yield) and generator expressions. When invoked, a generator function instantiates a PyGenObject without executing code. Calling next() enters the generator frame, executing instructions until a YIELD_VALUE opcode pauses execution and transfers control and data back to the caller.
Unlike standard functions whose stack frames are destroyed on return, a generator's PyFrameObject is preserved on the heap across suspension points. Its instruction pointer, local variables, and evaluation stack remain intact. When the generator finishes or returns, it raises StopIteration, passing any return value in the exception's value attribute.
Generators are single-pass streams. Once a generator raises StopIteration, all subsequent next() calls or for-loops immediately terminate without processing data. Passing an already-consumed generator into a second loop or aggregation function silently yields zero iterations without raising an error.
Interactive Dry-Run Execution Workspace
Sending to a Freshly Started Generator
Trace CPython execution step-by-step and deduce the exact stdout string emitted by this snippet.
def gen():
x = yield 1
yield x
g = gen()
try:
g.send(10)
except TypeError as e:
print('TypeError')Frequently Asked Questions on Generators & Iterators Protocols
What is the internal memory difference between a list comprehension and a generator expression?
A list comprehension eagerly constructs a full PyListObject containing all elements simultaneously in memory (O(N) space). A generator expression returns a PyGenObject that lazily evaluates items one by one on demand (O(1) space).
Can an exhausted generator be reset or rewound in Python?
No. In Python, exhausted generators cannot be rewound. To iterate over the sequence again, you must call the generator function to instantiate a brand-new PyGenObject or store items in a list using list(gen).
How does the 'yield from' expression simplify nested generator delegation?
yield from establishes a transparent two-way channel between the caller and an inner subgenerator. It automatically handles value yielding, exception propagation, and return value extraction without requiring manual while/try/except loops.