2012-04-04 12 views
5

Siempre pensé que iterar sobre un archivo en Python sería equivalente a llamar a su método readline en un bucle, pero hoy encontré una situación en la que eso no es cierto. Específicamente, tengo un proceso Popen 'd p dondeDiferencia entre iterar sobre una línea de lectura de llamada y de archivo

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

cuelga (presumiblemente porque p espera la entrada; tanto stdin y stdout son tuberías a mi proceso de Python), mientras que las siguientes obras:

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

¿Alguien puede explicar la diferencia?

+0

Nota al margen: en lugar de 'fiter()' puede usar 'iter (f.readline, None)', o incluso 'iter (f.readline," \ n ")' para reemplazar 'takewhile()'. –

+0

El problema que está viendo está relacionado con el almacenamiento en búfer: 'file .__ iter __()' hace de alguna manera un almacenamiento en búfer más agresivo que 'file.readline()' - esa es también la razón por la que no puede mezclarlos. Demasiado perezoso para investigar los detalles y convertir esto en una respuesta en este momento ... –

+0

@SvenMarnach: te refieres a 'iter (f.readline," ")', pero sí, gracias, me olvido de eso :) –

Respuesta

4

La diferencia radica puramente en la implementación de la iteración frente al método readline. La iteración de archivos se lee en bloques (de 8 kilobytes, de forma predeterminada) y luego divide el búfer en líneas a medida que las consumes. El método readline, por otro lado, se cuida de no leer nunca más de una línea, y eso significa leer carácter por carácter. Leer en bloques es mucho más eficiente, pero significa que no puede mezclar otras operaciones en el archivo entre lecturas. La expectativa es que cuando itere sobre el archivo, su intención es leer todas las líneas secuencialmente y no realizará otras operaciones en él. El método readline no puede hacer esa suposición.

Como Sven Marnach dio a entender en su comentario a su pregunta, puede utilizar iter(f.readline, '') para obtener un iterador que lee las líneas del archivo sin lectura en bloques, a costa de rendimiento.

+0

¿Sabes dónde en el código fuente CPython puedo encontrar la implementación de iteradores de archivos? –

+0

En 'Objects/fileobject.c'. Los objetos de archivo son sus propios iteradores, por lo que no hay un tipo diferente. 'file.readline' es' file_readline', y la iteración se realiza a través de 'file_iternext'. –

Cuestiones relacionadas