liveBook · Manning

Generator

As explained in Python How-To

A generator is a Python construct that produces a sequence of values incrementally through iteration rather than computing the entire sequence at once.

Need to sum a million squares without first storing a million numbers? A generator supplies values one at a time. It is an iterator: it produces the next value when requested rather than loading every value up front. section 7.4 section 7.4.1

Yield squares as they are needed

Set `upper_limit = 1_000_000`, then define `perfect_squares(limit)` with `n = 1` and a `while n <= limit` loop. Inside the loop, use `yield n * n`, followed by `n += 1`. Calling `squares = perfect_squares(upper_limit)` creates the generator; `sum(squares)` produces `333333833333500000`. Each `yield` pauses execution. The next request resumes after that `yield`, with `n` preserved. section 7.4.1

This on-demand behavior is a form of lazy evaluation. In the million-square comparison, the list reports a size of 8,448,712 bytes, while the generator reports 88 bytes. The generator retains its current state instead of storing the whole sequence. section 7.4 section 7.4.2

Use an expression for a simple sequence

`squares = (x * x for x in range(1, 5))` creates a generator without a separate function. `next(squares)` returns `1`; `sum(squares)` then returns `29`, not `30`, because the first value has already been consumed. For a one-off calculation, write `sum(x * x for x in range(1, 5))` instead. Parentheses distinguish a generator expression from a list comprehension, although the inner pair can be omitted in this `sum` call. section 7.4.3

Listing 11.15 Retrieving files of the same kind
data_folder = Path("data")
 
data_files = data_folder.glob("*.dat")
print("Data files:", data_files)                            #1
 
for data_file in data_files:
    print(f"Processing file: {data_file}")
    # applicable data processing steps here
 
# output the following lines:
Data files: <generator object Path.glob at 0x100b5c040>     #2
 
Processing file: data/subject_124.dat
Processing file: data/subject_125.dat
Processing file: data/subject_123.dat

`Path.glob("*.dat")` supplies matching files through a generator that a `for` loop can process. If another pass is needed after exhaustion, call `glob` again; sort the results when processing order matters. section 11.4.2

Prefer a generator expression for a straightforward, one-off sequence and a generator function when producing values needs a loop and explicit state. As practice, write a generator function that yields Fibonacci numbers up to a specified limit. section 7.4.3 section 7.4.5

How Python How-To covers it

How deep it goes
Explains creation, `yield` resumption, exhaustion, generator expressions, and memory use; leaves generator-based coroutines as a legacy aside.
Examples
Uses a million-square sum, a partially consumed generator expression, a Fibonacci exercise, and matching `.dat` files.
What it assumes
Assumes basic functions, loops, `range`, and `sum`; introduces `yield` and generator expressions through square calculations.
What you can do after
Build it from scratch with `yield`, or apply a generator expression to supply values on demand.
How it connects
Connects generators to iterators, lazy evaluation, list comprehensions, and `Path.glob`.

Also explained in

Compare how 12 books explain generator →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Python How-To. The section links point to the parts of the book it draws on.