Skip to main content
eLearner.app
Module 6 · Lesson 3 of 423/36 in the course~10 min
Module lessons (3/4)

Generator expression

A generator expression is like a list comprehension, but with parentheses instead of square brackets. The difference is dramatic: it doesn't build a list in memory, it produces elements on-demand, one at a time.

Python
gen = (n * n for n in range(1_000_000))
# istantaneo, memoria costante: nessun calcolo ancora fatto

list_comp = [n * n for n in range(1_000_000)]
# alloca 1M di int in memoria

Laziness (lazy evaluation)

The generator does nothing until someone asks for the next value:

Python
gen = (n * n for n in range(5))
next(gen)    # 0    (calcolato adesso)
next(gen)    # 1
next(gen)    # 4
# ... e così via, fino a StopIteration

It gets exhausted: after consuming all elements, it is empty forever. To reuse it, you must recreate it.

When to use it

When you pass the results to a function that consumes them in sequence:

Python
total = sum(n * n for n in range(1_000_000))
# nessuna lista intermedia, memoria costante

sum, any, all, max, min, "".join(...) all accept generators. If the outer function only requires the call parentheses, you can omit the generator's own:

Python
sum((n * n for n in range(10)))    # OK
sum(n * n for n in range(10))      # IDENTICO, più leggibile

any and all: short-circuit

any(...) and all(...) stop iterating as soon as they have the answer. With a generator, the following elements aren't even computed.

Python
nums = [1, 2, 3, 4, 5]
any(n > 3 for n in nums)    # True (si ferma a 4)
all(n > 0 for n in nums)    # True
all(n > 2 for n in nums)    # False (si ferma a 1)

Pattern: lazy pipeline

Python
righe = (linea.strip() for linea in testo.splitlines())
non_vuote = (r for r in righe if r)
prime_dieci = []
for r in non_vuote:
    prime_dieci.append(r)
    if len(prime_dieci) == 10:
        break

No intermediate list, even on huge inputs.

Consuming generators with sum, any, all

Generator expressions are perfect for passing directly to functions that consume iterables, like sum(), any(), or all(). In this case, you can omit the outer parentheses of the generator expression, simply writing:

Python
squares_sum = sum(x**2 for x in range(10))

This keeps your code clean and highly memory-efficient.

Try it

Exercise#python.m6.l3.e1
Attempts: 0Loading…

Compute the sum of the squares of the numbers from 1 to 100 (inclusive) using a generator expression inside sum(). Assign it to `tot`. Evaluate `tot`.

Loading editor…
Show hint

range(1, 101) includes 100.

Solution available after 3 attempts

Review exercise

Exercise#python.m6.l3.e2
Attempts: 0Loading…

Given `words = ['ciao', 'mondo', 'PYTHON', 'java']`, use any() with a generator expression to check whether AT LEAST one word is uppercase (.isupper()). Assign the result to `has_uppercase`. Evaluate `has_uppercase`.

Loading editor…
Show hint

any(p.isupper() for p in words)

Solution available after 3 attempts

Additional challenge

Exercise#python.m6.l3.e3
Attempts: 0Loading…

Use a generator expression passed directly to the `sum()` function to calculate the sum of the squares of all integers from 1 to 100 inclusive. Store the result in `total_sum` and evaluate it.

Loading editor…
Show hint

Write total_sum = sum(x**2 for x in range(1, 101)). Double parentheses are not needed.

Solution available after 3 attempts