2012-04-04 7 views
5

Ho sempre pensato che iterare su un file simile a Python equivalesse a chiamare il suo metodo readline in un ciclo, ma oggi ho trovato una situazione in cui ciò non è vero. Specificamente, ho un processo Popen 'd p doveDifferenza tra iterare su file e chiamare readline

list(itertools.takewhile(lambda x: x != "\n", 
         p.stdout)) 

hang (presumibilmente perché p attende input, sia stdin e stdout sono tubi al mio processo pitone), mentre i seguenti lavori:

list(itertools.takewhile(lambda x: x != "\n", 
         iter(p.stdout.readline, ""))) 

Qualcuno può spiegare la differenza?

+0

Nota a margine: invece di 'fiter()' si può usare 'iter (f.readline, None)', o anche 'iter (f.readline, "\ n")' 'per sostituire TakeWhile()'. –

+0

Il problema che state vedendo è legato a buffer: 'file di .__ __ iter()' fa il buffering in qualche modo più aggressivo rispetto 'file.readline()' - che è anche il motivo per cui non si possono mescolare. Troppo pigro per la ricerca dei dettagli e trasformare questo in una risposta in questo momento ... –

+0

@SvenMarnach: vuoi dire 'iter (f.readline, "")', ma sì, grazie, io continuo a dimenticare che :) –

risposta

4

La differenza è puramente nell'attuazione della iterazione rispetto al metodo readline. L'iterazione file viene letta in blocchi (di 8 kilobyte, per impostazione predefinita) e quindi divide il buffer in linee man mano che vengono consumati. Il metodo readline, d'altra parte, si prende cura di non leggere più di una riga, e ciò significa che la lettura di carattere per carattere. La lettura in blocchi è molto più efficiente, ma significa che non è possibile mescolare altre operazioni sul file tra le letture. L'aspettativa è che quando si sta iterando sul file, l'intento è quello di leggere tutte le righe in sequenza e non si faranno altre operazioni su di esso. Il metodo readline non può rendere questa ipotesi.

Come Sven Marnach accennato nel suo commento alla tua domanda, è possibile utilizzare iter(f.readline, '') per ottenere un iteratore che legge righe dal file senza lettura in blocchi, a costo di prestazioni.

+0

Sai dove nel codice sorgente CPython posso trovare l'implementazione degli iteratori di file? –

+0

In 'Objects/fileobject.c'. Gli oggetti file sono i loro iteratori, quindi non esiste un tipo separato. 'file.readline' è' file_readline', e l'iterazione viene eseguita tramite 'file_iternext'. –