Generatori Python: iteratori efficienti in termini di memoria

Scopri come utilizzare i generatori Python e le istruzioni yield per elaborare enormi set di dati con un ingombro di memoria minimo. Espressioni del generatore principale.

Prova nell'editor

Panoramica

Quando si scrive codice che elabora migliaia o milioni di record, la gestione della memoria diventa fondamentale. Se carichi un intero set di dati in un elenco, rischi di rimanere senza RAM e mandare in crash il server. I generatori Python risolvono questo problema fornendo un meccanismo per lo streaming di dati su richiesta. Invece di calcolare e archiviare l'intero set di dati in memoria in una volta, un generatore produce un elemento alla volta, lo fornisce al chiamante e ne mette in pausa l'esecuzione finché non viene richiesto l'elemento successivo.

I generatori sono definiti come normali funzioni, ma utilizzano la parola chiave "yield" invece di "return". Quando viene chiamata una funzione generatrice, restituisce un oggetto iteratore generatore senza eseguire le istruzioni interne della funzione. Quando il chiamante chiama `next()` sul generatore (o lo esegue in loop), la funzione viene eseguita finché non raggiunge `yield`. A quel punto, il generatore restituisce il valore, salva le sue variabili locali e sospende l'esecuzione. Quando viene richiamato di nuovo, riprende esattamente da dove era stato interrotto.

Puoi anche creare generatori utilizzando le espressioni del generatore, che utilizzano una sintassi identica alle comprensioni delle liste ma racchiuse tra parentesi "(...)" anziché tra parentesi "[...]". Ciò rende incredibilmente facile sostituire le comprensioni degli elenchi con iteratori efficienti in termini di memoria. Evitando massicce allocazioni di memoria, i generatori sono indispensabili per lavorare con log di grandi dimensioni, trasmettere dati da database o eseguire calcoli su sequenze matematiche di lunghezza infinita.

Codice e output di esecuzione

Un generatore personalizzato che produce numeri di Fibonacci e un'espressione del generatore efficiente in termini di memoria.

generators_demo.py
Prova nell'editor
def fibonacci_generator(limit):
    """Yields Fibonacci numbers up to the limit."""
    a, b = 0, 1
    count = 0
    while count < limit:
        yield a
        a, b = b, a + b
        count += 1

# Instantiate generator
fib = fibonacci_generator(5)
print("--- Using Generator Function ---")
for num in fib:
    print(num)

# Generator expression (squares of numbers)
squares_gen = (x**2 for x in range(1, 1000000))
print("\n--- Using Generator Expression ---")
print(next(squares_gen))
print(next(squares_gen))
print(next(squares_gen))
Uscita terminale
--- Using Generator Function ---
0
1
1
2
3

--- Using Generator Expression ---
1
4
9

Implementazione passo dopo passo

  • Lettura riga per riga di file troppo grandi per la RAM
  • Generazione di una sequenza infinita di ID o cifre matematiche
  • Streaming di record del database in batch per elaborare le chiamate API

Domande frequenti

Qual è la differenza tra rendimento e rendimento?

return termina completamente la funzione. yield restituisce un valore e mette in pausa la funzione, salvandone lo stato in modo che possa riprenderla quando richiesto.

Cosa succede quando un generatore esaurisce gli elementi?

Genera un'eccezione StopIteration. Sotto un ciclo 'for', Python intercetta automaticamente questa eccezione per terminare il ciclo in modo pulito.

Argomenti correlati

Risorse Python consigliate

Espandi le tue conoscenze con tutorial interattivi, foglietti illustrativi e confronti di codici correlati.