2009-10-06 7 views
12

¿Hay una mejor manera de leer las líneas dos a la vez desde un archivo en Python que:líneas de lectura 2 a la vez

with open(fn) as f: 
    for line in f: 
     try: 
      line2 = f.next() 
     except StopIteration: 
      line2 = '' 
     print line, line2 # or something more interesting 

estoy en 2.5.4. ¿Algo diferente en las versiones más nuevas?

EDITAR: se ha eliminado una respuesta: en py3k, debe hacer la siguiente (f) en lugar de f.next(). Por no mencionar el cambio de impresión

Respuesta

16
import itertools 

with open(fn) as f: 
    for line, line2 in itertools.izip_longest(f, f, fillvalue=''): 
    print line, line2 

Ay, izip_longest requiere Python 2.6 o superior; 2.5 solo tiene izip, que truncaría la última línea si f tiene un número impar de líneas. Es bastante fácil proporcionar la funcionalidad equivalente como generador, por supuesto.

Aquí hay una "N a la vez" más general iterador del envoltorio:

def natatime(itr, fillvalue=None, n=2): 
    return itertools.izip_longest(*(iter(itr),)*n, fillvalue=fillvalue) 

itertools es generalmente el mejor camino a seguir, pero, si se insistió en la aplicación por sí mismo, entonces:

def natatime_no_itertools(itr, fillvalue=None, n=2): 
    x = iter(itr) 
    for item in x: 
    yield (item,) + tuple(next(x, fillvalue) for _ in xrange(n-1)) 

En 2.5, creo que el mejor enfoque no es en realidad un generador, pero otra solución basada itertools-:

def natatime_25(itr, fillvalue=None, n=2): 
    x = itertools.chain(iter(itr), (fillvalue,) * (n-1)) 
    return itertools.izip(*(x,)*n) 

(ya que 2.5 no tiene incorporado next, así como izip_longest faltante).

+0

+1: sugerencia para el generador en Py2.5 –

+0

nunca prestó atención a el parámetro 'default' de' next', gracias por señalar eso. – SilentGhost

+0

try/except parece simple y claro (y no sería necesario si pudiéramos garantizar un número par de líneas). ¿Por qué preferirías escribir un generador aquí? ¿No necesitaría el generador una prueba/excepto? – foosion

1

para pequeñas y archivos de tamaño medio,

>>> data=open("file").readlines() 
>>> for num,line in enumerate(data[::2]): 
... print ''.join(data[num:num+2]) 
2

Usted podría hacerla más clara con un generador:

def read2(f): 
    for line in f: 
     try: 
      line2 = f.next() 
     except StopIteration: 
      line2 = '' 

     yield line, line2 

with open(fn) as f: 
    for line1, line2 in read2(f): 
     print line1 
     print line2 
Cuestiones relacionadas