Il punto importante è che la comprensione dell'elenco crea un nuovo elenco. Il generatore crea un oggetto iterabile che "filtra" al volo il materiale sorgente mentre si consumano i bit.
Immagina di avere un file di registro da 2 TB chiamato "hugefile.txt" e desideri il contenuto e la lunghezza di tutte le righe che iniziano con la parola "ENTRY".
Quindi prova a iniziare scrivendo una lista di comprensione:
logfile = open("hugefile.txt","r")
entry_lines = [(line,len(line)) for line in logfile if line.startswith("ENTRY")]
Ciò assorbe l'intero file, elabora ogni riga e memorizza le linee corrispondenti nell'array. Questo array può quindi contenere fino a 2 TB di contenuto. È molta RAM e probabilmente non è pratica per i tuoi scopi.
Quindi invece possiamo usare un generatore per applicare un "filtro" ai nostri contenuti. Nessun dato viene effettivamente letto fino a quando non si inizia a ripetere il risultato.
logfile = open("hugefile.txt","r")
entry_lines = ((line,len(line)) for line in logfile if line.startswith("ENTRY"))
Nemmeno una singola riga è stata ancora letta dal nostro file. In effetti, supponiamo di voler filtrare ulteriormente il nostro risultato:
long_entries = ((line,length) for (line,length) in entry_lines if length > 80)
Ancora nulla è stato letto, ma ora abbiamo specificato due generatori che agiranno sui nostri dati come desideriamo.
Consente di scrivere le nostre linee filtrate su un altro file:
outfile = open("filtered.txt","a")
for entry,length in long_entries:
outfile.write(entry)
Ora leggiamo il file di input. Mentre il nostro for
loop continua a richiedere linee aggiuntive, il long_entries
generatore richiede linee dal entry_lines
generatore, restituendo solo quelle la cui lunghezza è superiore a 80 caratteri. E a sua volta, il entry_lines
generatore richiede righe (filtrate come indicato) logfile
dall'iteratore, che a sua volta legge il file.
Quindi, invece di "spingere" i dati nella funzione di output sotto forma di un elenco completamente popolato, stai offrendo alla funzione di output un modo per "estrarre" i dati solo quando necessario. Nel nostro caso questo è molto più efficiente, ma non altrettanto flessibile. I generatori sono a senso unico, a passaggio; i dati del file di registro che abbiamo letto vengono immediatamente eliminati, quindi non possiamo tornare a una riga precedente. D'altra parte, non dobbiamo preoccuparci di conservare i dati una volta terminato.
[exp for x in iter]
essere solo zucchero perlist((exp for x in iter))
? o c'è una differenza di esecuzione?