Lezioni del modulo (3/4)
Generator expression
Una generator expression è come una list comprehension, ma con parentesi tonde invece che quadre. La differenza è radicale: non costruisce una lista in memoria, produce gli elementi on-demand, uno alla volta.
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 memoriaPigrizia (lazy evaluation)
Il generatore non fa nulla finché qualcuno non chiede il prossimo valore:
gen = (n * n for n in range(5))
next(gen) # 0 (calcolato adesso)
next(gen) # 1
next(gen) # 4
# ... e così via, fino a StopIterationSi esaurisce: dopo aver consumato tutti gli elementi, è vuoto per sempre. Per riusarlo devi ricrearlo.
Quando usarla
Quando passi i risultati a una funzione che li consuma in sequenza:
total = sum(n * n for n in range(1_000_000))
# nessuna lista intermedia, memoria costantesum, any, all, max, min, "".join(...) accettano tutti
generatori. Se la funzione esterna richiede solo le tonde di chiamata, puoi
omettere quelle del generatore:
sum((n * n for n in range(10))) # OK
sum(n * n for n in range(10)) # IDENTICO, più leggibileany e all: short-circuit
any(...) e all(...) smettono di iterare appena hanno la risposta. Con un
generatore, gli elementi successivi non vengono nemmeno calcolati.
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: pipeline pigra
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:
breakNessuna lista intermedia, anche su input enormi.
Consumare generatori con sum, any, all
Le generator expression sono ideali da passare direttamente come argomento a funzioni che consumano iterabili, come sum(), any() o all(). In questo caso, puoi omettere le parentesi tonde esterne della generator expression, scrivendo semplicemente:
somma_quadrati = sum(x**2 for x in range(10))Questo rende il codice incredibilmente leggibile ed estremamente efficiente.
Prova tu
Calcola la somma dei quadrati dei numeri da 1 a 100 (inclusi) usando una generator expression dentro sum(). Assegna a `tot`. Valuta `tot`.
Mostra suggerimento
range(1, 101) include 100.
Soluzione disponibile dopo 3 tentativi
Esercizio di ripasso
Data `words = ['ciao', 'mondo', 'PYTHON', 'java']`, usa any() con una generator expression per verificare se ALMENO una parola è in maiuscolo (.isupper()). Assegna a `has_uppercase`. Valuta `has_uppercase`.
Mostra suggerimento
any(p.isupper() for p in words)
Soluzione disponibile dopo 3 tentativi
Sfida aggiuntiva
Usa una generator expression passata direttamente alla funzione `sum()` per calcolare la somma dei quadrati di tutti i numeri interi da 1 a 100 (inclusi). Salva il risultato in `total_sum` e valutalo.
Mostra suggerimento
Scrivi total_sum = sum(x**2 for x in range(1, 101)). Non servono doppie parentesi.
Soluzione disponibile dopo 3 tentativi