Generators and yield

A function that pauses instead of returning, producing one value at a time and holding almost nothing in memory.

Overview

yield instead of return

def countdown(n):
    while n > 0:
        yield n
        n -= 1

return ends a function. yield suspends it, keeping every local variable exactly as it was, and the function continues from that line when the next value is requested.

Calling countdown(3) runs none of the body. It returns a generator object; the code inside starts running only when something asks for a value — next(), a for loop, list(), sum().

generators.py

generators.py Python 3
Output

                    

generator_memory.py

generator_memory.py Python 3
Output

                    

Worth knowing

yield pauses the function and hands a value back; the next request resumes it.
Calling a generator function runs none of its body - it returns a generator.
A generator is exhausted after one pass. Rebuild it to iterate again.
(x for x in y) is a generator expression - a comprehension with round brackets.

Generators and yield: A Practical Guide

A generator is a function that pauses. Instead of computing everything and returning it, it hands back one value, freezes, and resumes where it stopped when the next value is asked for.

Why bother

Memory. A list comprehension over a million items builds a million items. A generator holds a position and the local variables, which is a fixed few hundred bytes whatever the size — the page prints both.

That is what makes infinite sequences possible:

def naturals():
    n = 1
    while True:
        yield n
        n += 1

Nothing is built up front, so there is nothing to run out of. Take what you need with itertools.islice.

Exhausted after one pass

g = countdown(2)
list(g)  # [2, 1]
list(g)  # []

A generator walks forward once and does not rewind. If you need the values twice, either store them in a list or call the generator function again to get a fresh one. This catches everyone once, usually as a mysteriously empty second loop.

Generator expressions

(n * n for n in nums)

Round brackets instead of square. Identical syntax to a comprehension, no list built. Inside a call you can drop the extra brackets: sum(n * n for n in nums).

Pipelines

Generators compose. Each stage pulls from the one before it, so a chain of three generators still holds one value at a time:

doubled(evens(naturals()))

No stage stores anything, and nothing runs until the end of the chain is asked for a value. That is the pattern behind most stream processing in Python, and it is why generators are worth the concept even when memory is not tight.

Check yourself

0 of 3

Answer without scrolling back up.

  1. What does calling a generator function do?

  2. `list(g)` twice on the same generator gives what the second time?

  3. How does `(x*x for x in nums)` differ from `[x*x for x in nums]`?

Cheat sheet

Generators and yield

A generator is a function that pauses. Instead of computing everything and returning it, it hands back one value, freezes, and resumes where it stopped when the next value is asked for.

PYTHON · vizlearn.in/python/generators_and_yield.html

About the author

Ashish Jangra builds and maintains VizLearn. Every module here is written and the visualisation behind it hand-built, so the numbers in a readout come from the same code that draws the picture. Corrections are genuinely welcome and get priority over everything else — if a page states something wrong, or an animation misrepresents what the algorithm does, get in touch.