2012-02-14 8 views
113

Estoy viendo cómo hacer entrada y salida de archivos en Python. He escrito el siguiente código para leer una lista de nombres (uno por línea) de un archivo a otro archivo mientras comparo un nombre con los nombres en el archivo y agrego texto a las ocurrencias en el archivo. El código funciona ¿Podría hacerse mejor?Cómo abrir un archivo usando la declaración abierta con

Quería utilizar la declaración with open(... para los archivos de entrada y salida, pero no puedo ver cómo podrían estar en el mismo bloque, lo que significa que necesitaría almacenar los nombres en una ubicación temporal.

def filter(txt, oldfile, newfile): 
    '''\ 
    Read a list of names from a file line by line into an output file. 
    If a line begins with a particular name, insert a string of text 
    after the name before appending the line to the output file. 
    ''' 

    outfile = open(newfile, 'w') 
    with open(oldfile, 'r', encoding='utf-8') as infile: 
     for line in infile: 
      if line.startswith(txt): 
       line = line[0:len(txt)] + ' - Truly a great person!\n' 
      outfile.write(line) 

    outfile.close() 
    return # Do I gain anything by including this? 

# input the name you want to check against 
text = input('Please enter the name of a great person: ')  
letsgo = filter(text,'Spanish', 'Spanish2') 
+0

"lo que significa que necesitaría almacenar los nombres en una ubicación temporal"? ¿Puedes explicar a qué te refieres con esto? –

+2

Tenga en cuenta que 'filter()' es [una función incorporada] (https://docs.python.org/2/library/functions.html#filter) por lo que probablemente debería elegir un nombre diferente para su función. – Tom

+0

@Tom hace que una función en el espacio de nombres anule la función incorporada? – UpTide

Respuesta

195

Python permite poner múltiples open() declaraciones en una sola with. Usted coma separados. El código sería entonces:

def filter(txt, oldfile, newfile): 
    '''\ 
    Read a list of names from a file line by line into an output file. 
    If a line begins with a particular name, insert a string of text 
    after the name before appending the line to the output file. 
    ''' 

    with open(newfile, 'w') as outfile, open(oldfile, 'r', encoding='utf-8') as infile: 
     for line in infile: 
      if line.startswith(txt): 
       line = line[0:len(txt)] + ' - Truly a great person!\n' 
      outfile.write(line) 

# input the name you want to check against 
text = input('Please enter the name of a great person: ')  
letsgo = filter(text,'Spanish', 'Spanish2') 

Y no, no se gana nada por poner explícita return al final de su función. Puede usar return para salir temprano, pero lo tenía al final, y la función saldrá sin él. (Por supuesto, con las funciones que devuelven un valor, se utiliza el return para especificar el valor a devolver.)

el uso de múltiples open() elementos con with no fue apoyada en Python 2.5, cuando se introdujo la declaración with, o en Python 2.6, pero es compatible con Python 2.7 y Python 3.1 o posterior.

http://docs.python.org/reference/compound_stmts.html#the-with-statement http://docs.python.org/release/3.1/reference/compound_stmts.html#the-with-statement

Si está escribiendo código que debe ejecutarse en Python 2.5, 2.6 o 3.0, el nido de with declaraciones como las otras respuestas sugeridas o uso contextlib.nested.

8

Puede anidar con bloques. De esta manera:

with open(newfile, 'w') as outfile: 
    with open(oldfile, 'r', encoding='utf-8') as infile: 
     for line in infile: 
      if line.startswith(txt): 
       line = line[0:len(txt)] + ' - Truly a great person!\n' 
      outfile.write(line) 

Esto es mejor que su versión, ya que garantiza que outfile estará cerrada incluso si su código se encuentra con excepciones. Obviamente, puedes hacer eso con try/finally, pero with es la forma correcta de hacerlo.

O, como acabo de enterarme, puede tener varios gestores de contexto en una instrucción with como described by @steveha. Esa me parece una mejor opción que anidar.

Y para su última pregunta menor, la devolución no sirve para nada. Yo lo eliminaría

+0

Muchas gracias. Lo intentaré y aceptaré tu respuesta si/cuando lo ponga a funcionar. – Disnami

+0

Gracias de nuevo. Tengo que esperar siete minutos antes de poder aceptar. – Disnami

+5

@Disnami asegúrate de aceptar la respuesta correcta (¡y esta no es esta!) ;-) –

18

Use bloques anidados como este,

with open(newfile, 'w') as outfile: 
    with open(oldfile, 'r', encoding='utf-8') as infile: 
    #your logic goes here 
Cuestiones relacionadas