Foundations — Generators — yield, generator functions, send(), next()
Before you can trust the parent note Generators — yield, generator functions, send(), next() (index 1.3.9), you must own every word inside that sentence. We build them from nothing, in the order they depend on each other.
0. What is a "function" doing when it runs?
Start below zero. A normal function is a set of instructions Python reads top to bottom. When you call it — write its name with () — Python jumps into the body, runs every line, and the moment it hits return (or the last line) the function is over and forgotten.
The phrase erase my scratch paper matters. When a function ends, every local variable it made vanishes. Picture a whiteboard the function writes on and then wipes clean the instant it returns.

Look at the left column: a normal call is a straight fall from top to bottom into a wiped board. Hold this picture — the whole topic is about NOT wiping the board.
Why does the topic need this? Because a generator's superpower is precisely keeping the whiteboard. You cannot appreciate the trick until you see the ordinary thing it breaks.
1. The stack frame — the "whiteboard" made concrete
When a function runs, Python builds a private scratch space for it called a stack frame. Two things live there:
- Every local variable (like
i = 0). - A hidden pointer to the current line — Python's finger on "we are here."
You need this concept because the parent note claims a generator "remembers exactly where it stopped." Where = the finger on the current line. What = the frozen box of locals.
2. yield — the freeze word
Now the keyword everything is named after.
Compare the two exits a function can take:
| word | value out | what happens to the frame |
|---|---|---|
return x |
once | thrown away — done forever |
yield x |
once per yield | frozen and kept — can resume |

The red arrow is the resume jump — the thing a normal function can never do. Follow it: value goes out at yield, then later the finger hops back in and lands on the very next line, with i still holding its old value.
Why this word and not return? Because the topic needs a value to leave the function without ending it. return cannot do that — it always ends. yield is the only exit that says "pause, not stop."
3. Iterator, iterable, and the protocol — the rules of "pulling"
A generator hands out values one pull at a time. Python has a fixed contract for "things you pull from one at a time," borrowed from Iterators and the Iterator Protocol.
Think of an iterable as a box of tickets and the iterator as the hand that draws one ticket per pull. Some objects (like generators) are their own hand — the box and the hand are the same thing.
Why the topic needs it: the parent note runs next(g) over and over. That word is literally "turn the tap one more sip."
4. StopIteration — the "there are no more" signal
What happens when the tap runs dry? The iterator can't return a value (there is none) and it can't return None (that would look like a real value). So Python uses an exception — a special "stop everything" signal — to mean empty.

The state machine shows the two exits of every next(): the black loop (a value came out) and the red bell (StopIteration, we are done). A for loop is exactly this diagram automated.
5. yield as an expression — the doorway send() uses
So far yield only pushes values out. But the parent note writes x = yield average. How can yield also bring a value in?
Why the topic needs this: it is the difference between a generator (talks out) and a coroutine (talks both ways). Everything about send() in the parent stands on this single fact — yield is an expression, not just a statement.
6. Laziness — why any of this is worth it
Because a generator only runs a piece of its body per pull, it never builds the whole result at once. This is lazy evaluation — see Lazy Evaluation and List Comprehensions vs Generator Expressions.
Prerequisite map
Read it top to bottom: the plain function idea feeds the frame idea, the frame idea makes yield possible, and the pulling protocol plus laziness all pour into the generators topic.
Equipment checklist
Cover the right side and answer each aloud. If any stalls, re-read its section before touching the parent note.
What does return do to a function's local variables?
What two things live inside a stack frame?
What does yield value do that return value cannot?
What is the difference between an iterable and an iterator?
__iter__); an iterator is the puller itself (has __next__).What is next(g) shorthand for?
g.__next__() — pull one value, running the body to the next yield.Why does an exhausted iterator raise StopIteration instead of returning something?
for loop listens for.In x = yield v, where does the value stored in x come from?
g.send(...) (or None if next was used) — because yield is a two-way expression.Why must you prime a generator with next(g) before send(v)?
yield is reached there is no paused yield expression to receive v.