Vai al contenuto
eLearner.app
Modulo 6 · Lezione 3 di 423/36 nel corso~10 min
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.

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

Pigrizia (lazy evaluation)

Il generatore non fa nulla finché qualcuno non chiede il prossimo valore:

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

Si 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:

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

sum, any, all, max, min, "".join(...) accettano tutti generatori. Se la funzione esterna richiede solo le tonde di chiamata, puoi omettere quelle del generatore:

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

any e all: short-circuit

any(...) e all(...) smettono di iterare appena hanno la risposta. Con un generatore, gli elementi successivi non vengono nemmeno calcolati.

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: pipeline pigra

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

Nessuna 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:

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

Questo rende il codice incredibilmente leggibile ed estremamente efficiente.

Prova tu

Esercizio#python.m6.l3.e1
Tentativi: 0Caricamento…

Calcola la somma dei quadrati dei numeri da 1 a 100 (inclusi) usando una generator expression dentro sum(). Assegna a `tot`. Valuta `tot`.

Caricamento editor…
Mostra suggerimento

range(1, 101) include 100.

Soluzione disponibile dopo 3 tentativi

Esercizio di ripasso

Esercizio#python.m6.l3.e2
Tentativi: 0Caricamento…

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`.

Caricamento editor…
Mostra suggerimento

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

Soluzione disponibile dopo 3 tentativi

Sfida aggiuntiva

Esercizio#python.m6.l3.e3
Tentativi: 0Caricamento…

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.

Caricamento editor…
Mostra suggerimento

Scrivi total_sum = sum(x**2 for x in range(1, 101)). Non servono doppie parentesi.

Soluzione disponibile dopo 3 tentativi