yield keyword and generator functions

RoadmapsPython

Overview

A generator function is a function that contains the `yield` keyword. Unlike a normal function that computes a result and returns it all at once, a generator function pauses its execution at each `yield`. This returns a value to the caller while keeping its local variables and execution pointer intact. When `next()` is called on it again, it resumes exactly where it left off. def count_up_to(max_val): count = 1 while count <= max_val: yield count count += 1 You can think of a generator function as a resumable machine. Instead of building the entire product and handing it over at the end, it spits out one piece on demand, pauses, and waits for you to ask for the next piece. def return_in_gen(): yield 1 return "Finished" g = return_in_gen() next(g) # Returns 1 next(g) # Raises StopIteration("Finished") When a generator executes a `return` statement, it raises a `StopIteration` exception, and the returned value becomes the exception's argument. This behavior is critical when delegating generators, covered fully in yield-from.

Generators allow you to produce sequences of values over time without having to load all of them into memory at once, enabling efficient processing of large datasets, infinite sequences, or streams.

Where used: `FastAPI` dependency injection (`yield` for cleanup), `pytest` fixtures (`yield` for teardown), Processing large CSV files or database queries

Why learn this

Code walkthrough

def one_two_three():
    yield 1
    yield 2
    yield 3

gen = one_two_three()
print(next(gen))
print(next(gen))

Focus: print(next(gen))

Aha moment

def tricky_gen():
    print('Starting')
    yield 1
    print('Continuing')
    yield 2

g = tricky_gen()
print('Created generator')

Prediction: What does this print when executed?

Common guess: `'Starting'`, then `'Created generator'`

Calling `tricky_gen()` only creates the generator object; it doesn't execute the function body at all. The code inside the generator function only runs when `next()` or a `for` loop is used, so `'Starting'` is never printed here.

Common mistakes

Glossary

local state
The current values of variables that exist only within a specific function and are usually lost when the function ends. Example: `count = 0` inside a function.
execution pointer
An internal marker that keeps track of exactly which line of code a program is currently running or paused at. Example: pausing at `yield 1`.

Recall questions

Understanding checks

What does the following code print?

`1`

Calling `next(g)` resumes the generator, executing it until the first `yield` statement, which returns `1`.

A developer expects calling `process_data()` to immediately execute the first part of the function and print `'Starting...'`. Why doesn't it?

Because `process_data()` is a generator function, calling it only returns a generator object. It doesn't start executing the body.

A generator function's body only begins running when `next()` is called on the resulting generator object or when it is iterated over.

What exception is raised when you call `next(g)` a second time on this generator?

`StopIteration('b')`

When a generator hits a `return` statement, it raises a `StopIteration` exception with the returned value attached to it.

Practice tasks

Convert List to Generator

The `countdown` function currently builds a complete `list` of numbers in memory and returns it. Modify it to be a generator function that `yield`s each number one by one instead.

Challenge

Batch Processor

Write a generator function `batch_items(items, batch_size)` that takes a `list` of `items` and yields sub-lists of length `batch_size`. If the remaining items are fewer than `batch_size`, `yield` them as the final batch. For example, `list(batch_items([1, 2, 3, 4, 5], 2))` should result in `[[1, 2], [3, 4], [5]]`.

Continue learning

Previous: Defining functions and return values

Previous: The Iterable Protocol

Previous: Iterator Protocol and StopIteration

Previous: iter() and next() builtins

Next: Lazy Evaluation and Memory Efficiency

Next: yield from and generator delegation

Next: Generator send() for Two-Way Communication

Return to Python Roadmap