Gli iteratori e i generatori sono alla base della gestione efficiente delle sequenze in Python. Storicamente, Python ha cercato di semplificare il lavoro con i flussi di dati e di evitare l'eccessivo stoccaggio di grandi collezioni in memoria. Innanzitutto è stato introdotto il supporto per gli iteratori tramite i protocolli __iter__ e __next__, e poi i generatori, che consentono di creare semplici iteratori tramite costrutti basati su yield.
Problema: è spesso necessario gestire grandi volumi di dati (ad esempio, streaming da file o database), il che non è possibile fare comodamente ed efficientemente se si carica tutto in memoria contemporaneamente. Le normali funzioni restituiscono tutti i risultati contemporaneamente e la creazione di iteratori personalizzati tramite classi è spesso troppo ingombrante per casi semplici.
Soluzione: il meccanismo yield consente di organizzare la generazione "pigra" dei dati. Una funzione generatore non restituisce un elenco o un'altra collezione, ma restituisce un oggetto generatore — un iteratore che calcola i valori al bisogno.
Esempio di codice:
# Semplice generatore def countdown(n): while n > 0: yield n n -= 1 for i in countdown(3): print(i) # 3, 2, 1
Caratteristiche chiave:
Si possono usare return e yield nella stessa funzione?
Sì, ma return in un generatore termina l'iterazione (solleva StopIteration), mentre yield può essere usato quante volte si desidera.
def example(): yield 1 return # StopIteration
Perché non si può "riavviare" un generatore dopo il termine?
Un generatore dopo la conclusione delle iterazioni (StopIteration) non può essere riavviato, deve essere creato nuovamente.
gen = countdown(2) list(gen) # [2, 1] list(gen) # [] (il generatore è già esaurito)
Qual è la differenza tra un generatore e un iteratore?
Un generatore è un caso particolare di iteratore; qualsiasi oggetto con i metodi iter e next è un iteratore, ma un generatore è creato tramite una funzione con yield.
Uno sviluppatore ha scritto una funzione che carica un milione di righe da un file in memoria tramite list(fd) per l'analisi. Questo ha portato a un overflow di memoria sul server.
Vantaggi:
Svantaggi:
Utilizzo di un generatore per la lettura riga per riga di un file e analisi dei dati al volo tramite yield.
Vantaggi:
Svantaggi: