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.
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 memoriaLaziness (lazy evaluation)
The generator does nothing until someone asks for the next value:
gen = (n * n for n in range(5))
next(gen) # 0 (calcolato adesso)
next(gen) # 1
next(gen) # 4
# ... e così via, fino a StopIterationIt 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:
total = sum(n * n for n in range(1_000_000))
# nessuna lista intermedia, memoria costantesum, any, all, max, min, "".join(...) all accept generators.
If the outer function only requires the call parentheses, you can
omit the generator's own:
sum((n * n for n in range(10))) # OK
sum(n * n for n in range(10)) # IDENTICO, più leggibileany 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.
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
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:
breakNo 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:
squares_sum = sum(x**2 for x in range(10))This keeps your code clean and highly memory-efficient.
Try it
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`.
Show hint
range(1, 101) includes 100.
Solution available after 3 attempts
Review exercise
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`.
Show hint
any(p.isupper() for p in words)
Solution available after 3 attempts
Additional challenge
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.
Show hint
Write total_sum = sum(x**2 for x in range(1, 101)). Double parentheses are not needed.
Solution available after 3 attempts