Cómo abrir un archivo usando la instrucción open with

Estoy viendo cómo hacer la 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 en otro archivo mientras se compara un nombre con los nombres en el archivo y se agrega texto a las ocurrencias en el archivo. El código funciona. ¿Se podría hacer mejor?

Quería usar la instrucció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') 

Python permite poner varias declaraciones open() en una sola with . Los separas con coma. Tu 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 gana nada al poner un return explícito al final de su función. Puede usar return para salir temprano, pero lo tuvo al final, y la función se cerrará sin él. (Por supuesto, con las funciones que devuelven un valor, se usa la return para especificar el valor para devolver).

El uso de varios elementos open() con no fue compatible con Python 2.5 cuando se introdujo la instrucción with , o en Python 2.6, pero sí se admite en Python 2.7 y Python 3.1 o más reciente.

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 un código que debe ejecutarse en Python 2.5, 2.6 o 3.0, anide los enunciados with las otras respuestas sugeridas o use contextlib.nested .

Usa bloques nesteds como este,

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

Puedes anidar tu con bloques. Me gusta esto:

 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 porque garantiza que se cerrará outfile incluso si su código encuentra excepciones. Obviamente, podrías hacer eso con intentar / finalmente, pero with es la forma correcta de hacerlo.

O, como acabo de enterarme, puede tener múltiples administradores de contexto en una statement with tal como lo describe @steveha . Me parece que es una mejor opción que anidar.

Y para su última pregunta menor, la devolución no tiene ningún propósito real. Yo lo eliminaría.

A veces, es posible que desee abrir una cantidad variable de archivos y tratar a cada uno de la misma manera, puede hacerlo con contextlib

 from contextlib import ExitStack filenames = [file1.txt, file2.txt, file3.txt] with open('outfile.txt', 'a') as outfile: with ExitStack() as stack: file_pointers = [stack.enter_context(open(file, 'r')) for file in filenames] for fp in file_pointers: outfile.write(fp.read())