Generator expressions

RoadmapsPython Backend

Overview

A generator expression looks just like a list comprehension, but uses parentheses `()` instead of square brackets `[]`. Instead of building an entire list in memory all at once, a generator expression uses lazy evaluation. It calculates and yields exactly one item at a time, pausing execution until the next item is requested. This means a generator expression takes up virtually no memory, regardless of how many items it will eventually produce. You can use them directly inside aggregation functions (functions that compute a single result from many values) like `sum()`, `max()`, or `any()`.

When processing millions of database rows or gigabytes of log files, loading the entire dataset into memory with a list comprehension will crash your application with an OutOfMemory error. Generator expressions allow you to process massive datasets in a constant O(1) memory footprint.

Where used: Aggregating data directly (e.g. `sum(x for x in data)`), Reading large files line-by-line, Processing streams of API data

Why learn this

Code walkthrough

numbers = [1, 2, 3]
gen = (x * 10 for x in numbers)

print(next(gen))
print(next(gen))
print(next(gen))

Focus: The `next()` function pulls exactly one value out of the generator expression at a time, proving it evaluates lazily.

Aha moment

gen = (x for x in [1, 2, 3])

first_pass = list(gen)
second_pass = list(gen)

print(second_pass)

Prediction: What will `second_pass` contain?

Common guess: [1, 2, 3]

A generator expression is consumed as it is read. The `first_pass` exhausted the generator. When `second_pass` tried to read from it, there were no items left, returning an empty list.

Common mistakes

Glossary

lazy evaluation
Computing or fetching values only exactly when they are needed, rather than all at once in advance. Example: `(x*2 for x in range(10))` — values are computed one at a time, not all upfront.
random-access
The ability to instantly retrieve an item at any specific position in a collection, like getting the 5th item in a list. Example: `my_list[4]` fetches the 5th element in constant time.

Recall questions

Understanding checks

What is the output of the second print statement?

`[]`

A generator expression is evaluated lazily and exhausted as it is consumed. The first `list(gen)` consumes all items. The second `list(gen)` finds an empty generator.

A junior developer is confused why `my_gen[0]` raises a TypeError when `my_gen` is a generator expression. How do you explain it?

Generator expressions do not support indexing because their items are evaluated lazily one at a time.

Unlike lists, which hold all their items in memory at once and support random access, generators only know how to produce the next item.

Practice tasks

Memory-efficient sum

Change the list comprehension to a generator expression to calculate the sum of squares without allocating memory for the entire list.

Challenge

Any big numbers?

Using a generator expression with the `any()` function, check if there are any numbers greater than 100 in `nums`. Assign the boolean result to `has_big`.

Continue learning

Previous: Comprehensions

Return to Python Backend Roadmap