abrir leer y cerrar un archivo en 1 línea de código

128

Ahora uso:

pageHeadSectionFile = open('pagehead.section.htm','r')
output = pageHeadSectionFile.read()
pageHeadSectionFile.close()

Pero para que el código se vea mejor, puedo hacer:

output = open('pagehead.section.htm','r').read()

Cuando uso la sintaxis anterior, ¿cómo cierro el archivo para liberar recursos del sistema?

1qazxsw2
fuente
19
No hay nada intrínsecamente más atractivo sobre las frases sencillas. El código se lee con mucha más frecuencia de lo que se escribe, y debe escribirse para su comprensión, no para su "frialdad". La única excepción es cuando hay un idioma bien conocido en un idioma, pero no estoy al tanto de uno en este caso.
drdwilcox
17
@drdwilcox: las frases crípticas son malas, las frases declarativas son buenas. No hay ninguna razón (al menos no puedo ver una), por qué no hay un contenedor de funciones en el núcleo para leer un archivo (una necesidad tan común) en una sola llamada de función. Algo así como contents = os.readfile(path). Si quisiera hacer algo más elegante, entonces bien, me encantaría usarlo with open(path) as fd: contents = fd.read(). Por supuesto, uno puede escribir su propio contenedor, pero para eso está el núcleo, para proporcionar lo útil a las abstracciones a los programadores.
tokland
55
Es cierto que el código se lee mucho más de lo que se escribe, pero la implicación de que el código más largo es tan bueno como el código corto no podría estar más equivocado. Si invierte tiempo en hacer su código lo más corto posible (sin recurrir a trucos ingeniosos que son difíciles de entender), esa inversión dará sus frutos una y otra vez cuando se lea el código. Cada línea que escribe es un mal servicio para cualquiera que lea su código, por lo que debe esforzarse por escribir lo menos posible. Recuerde la famosa cita de Pascal: "Hice esta carta más larga solo porque no he tenido el tiempo libre para acortarla".
John Williams

Respuestas:

195

Realmente no tiene que cerrarlo: Python lo hará automáticamente durante la recolección de basura o al salir del programa. Pero como señaló @delnan, es una mejor práctica cerrarlo explícitamente por varias razones.

Entonces, qué puede hacer para que sea breve, simple y explícito:

with open('pagehead.section.htm','r') as f:
    output = f.read()

Ahora son solo dos líneas y bastante legible, creo.

Tim Pietzcker
fuente
2
@ 1qazxsw2 Si usa la withdeclaración, el recurso de archivo se cerrará correctamente para usted.
David Alber
13
Re primera oración: Python lo cerrará eventualmente . Pero eso no significa que deba olvidarse del cierre. Incluso con el recuento, el archivo puede permanecer abierto mucho más tiempo de lo que piensa y desea (por ejemplo, si se hace referencia a él por ciclos). Esto va tres veces en implementaciones de Python que tienen un GC decente, donde no tienes garantía de que algo sea GC'd en ningún momento en particular. Incluso la documentación de CPython dice que no debe confiar en GC para una limpieza como esta. La última parte de la respuesta debe estar en negrita.
66
Si realmente necesita una línea , es posible colocar la output = f.read()pieza en la misma línea después de :.
Karl Knechtel el
1
"abrir leer y cerrar un archivo en 1 línea de código" son dos líneas y no responden la pregunta.
user5359531
1
Eso depende de la implementación: vea la respuesta de Sven.
Tim Pietzcker
71

El módulo Pathlib de la biblioteca estándar de Python hace lo que está buscando:

Path('pagehead.section.htm').read_text()

No olvides importar Ruta:

jsk@dev1:~$ python3
Python 3.5.2 (default, Sep 10 2016, 08:21:44)
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from pathlib import Path
>>> (Path("/etc") / "hostname").read_text()
'dev1.example\n'

En Python 27, instale backported pathlibopathlib2

Janusz Skonieczny
fuente
8
Las otras respuestas que proponen withestán bien, pero withes una declaración, no una expresión. Esta pathlibrespuesta es la única respuesta a la pregunta original que se puede incrustar en una expresión de Python. Algo así comoSECRET_KEY = os.environ.get('SECRET_KEY') or pathlib.Path('SECRET_KEY').read_bytes()
LeoRochael
24

Usando CPython, su archivo se cerrará inmediatamente después de que se ejecute la línea, porque el objeto del archivo se recolecta inmediatamente como basura. Sin embargo, hay dos inconvenientes:

  1. En implementaciones de Python diferentes a CPython, el archivo a menudo no se cierra de inmediato, sino más tarde, más allá de su control.

  2. En Python 3.2 o superior, esto arrojará un ResourceWarning, si está habilitado.

Es mejor invertir una línea adicional:

with open('pagehead.section.htm','r') as f:
    output = f.read()

Esto asegurará que el archivo se cierre correctamente en todas las circunstancias.

Sven Marnach
fuente
17

No es necesario importar ninguna biblioteca especial para hacer esto.

Use la sintaxis normal y abrirá el archivo para leerlo y luego lo cerrará.

with open("/etc/hostname","r") as f: print f.read() 

o

with open("/etc/hosts","r") as f: x = f.read().splitlines()

que le da una matriz x que contiene las líneas, y puede imprimirse así:

for line in x: print line

Estas frases son muy útiles para el mantenimiento, básicamente autodocumentadas.

SDsolar
fuente
8

Lo que puede hacer es usar la withdeclaración y escribir los dos pasos en una línea:

>>> with open('pagehead.section.htm', 'r') as fin: output = fin.read();
>>> print(output)
some content

La withdeclaración se encargará de llamar a la __exit__función del objeto dado incluso si algo malo sucedió en su código; Está cerca de la try... finallysintaxis. Para el objeto devuelto por open, __exit__corresponde al cierre del archivo.

Esta declaración se ha introducido con Python 2.6.

Joël
fuente
Pequeña aclaración: según la documentación with se introdujo en Python 2.5, pero tuvo que importarse explícitamente desde __future__. Se hizo disponible desde todos los contextos en Python 2.6.
David Alber
5

use ilio : (io en línea):

solo una llamada de función en lugar de abrir (), leer (), cerrar ().

from ilio import read

content = read('filename')
iman
fuente
2
with open('pagehead.section.htm')as f:contents=f.read()

fuente
44
¿En qué se diferencia esto de las 3 respuestas principales?
Todos los trabajadores son esenciales
44
La mayor diferencia es que es solo una línea como la pregunta especificada. Personalmente, no puedo encontrar más allá de eso, pero siéntase libre de criticar mi trabajo en lugar de contribuir a la pregunta usted mismo.
3
La forma más corta e integrada para lograr abrir, leer y cerrar un archivo en Python es usar 2 líneas lógicas, ya sea que se condense en 1 línea o no. Así que no veo que esta respuesta sea efectivamente diferente de las 3 respuestas originales.
Todos los trabajadores son esenciales
1
No importa si es "efectivamente" diferente. Llegué a esta página en busca de una sintaxis de una línea que podría usarse python -cen la línea de comando, por lo que publicar respuestas de 2 líneas no ayuda.
user5359531
1
@ user5359531 No veo su punto: ¿sabe que puede citar expresiones de python ", usar ;para agregar dos instrucciones y eliminar una nueva línea después :? La siguiente expresión funciona bien para mí:$> python -c "with open('some file', 'r') as f: print(next(f))"
Joël
2

Creo que la forma más natural de lograr esto es definir una función.

def read(filename):
    f = open(filename, 'r')
    output = f.read()
    f.close()
    return output

Entonces puedes hacer lo siguiente:

output = read('pagehead.section.htm')
Adrien Pavao
fuente
0

Con frecuencia hago algo como esto cuando necesito obtener algunas líneas que rodean algo que he agrupado en un archivo de registro:

$ grep -n "xlrd" requirements.txt | awk -F ":" '{print $1}'
54

$ python -c "with open('requirements.txt') as file: print ''.join(file.readlines()[52:55])"
wsgiref==0.1.2
xlrd==0.9.2
xlwt==0.7.5
Matthew Purdon
fuente
1
Nada que ver con el tema original, pero usted debe buscar en grep -A <n>, grep -B <n>y grep -C <n>, si es útil. Más información: stackoverflow.com/a/9083/1830159
Liam Stanley
0

Utilizando more_itertools.with_iter, es posible abrir, leer, cerrar y asignar un equivalente outputen una línea (excluyendo la declaración de importación):

import more_itertools as mit


output = "".join(line for line in mit.with_iter(open("pagehead.section.htm", "r")))

Aunque es posible, buscaría otro enfoque que no sea asignar el contenido de un archivo a una variable, es decir, la iteración perezosa; esto se puede hacer usando un withbloque tradicional o en el ejemplo anterior quitando join()e iterando output.

pylang
fuente
También puede importar dentro del oneliner. "".join(line for line in __import__('more_itertools').with_iter(open("pagehead.section.htm", "r")))Esto funciona bien y elimina la necesidad de una línea para la importación.
melwil
1
Estoy completamente de acuerdo contigo. Sin embargo, mientras discutía la resolución de tareas con los usuarios de línea, a menudo me encontraba en argumentos en los que el resultado acordado debería ser una sola línea de código pegada en un nuevo shell de Python. Tales desafíos rara vez se ajustan a pep8. De ninguna manera es una buena práctica escribir código, solo fue un consejo para eliminar la necesidad de importar.
melwil
0

Si quieres esa sensación cálida y difusa, simplemente ve con .

Para Python 3.6 ejecuté estos dos programas bajo un nuevo comienzo de IDLE, dando tiempos de ejecución de:

0.002000093460083008  Test A
0.0020003318786621094 Test B: with guaranteed close

Así que no hay mucha diferencia.

#--------*---------*---------*---------*---------*---------*---------*---------*
# Desc: Test A for reading a text file line-by-line into a list
#--------*---------*---------*---------*---------*---------*---------*---------*

import sys
import time

#                                  # MAINLINE
if __name__ == '__main__':
    print("OK, starting program...")

    inTextFile = '/Users/Mike/Desktop/garbage.txt'

#                                  # Test: A: no 'with;
    c=[]
    start_time = time.time()
    c = open(inTextFile).read().splitlines()
    print("--- %s seconds ---" % (time.time() - start_time))

    print("OK, program execution has ended.")
    sys.exit()                     # END MAINLINE

SALIDA:

OK, starting program...
--- 0.002000093460083008 seconds ---
OK, program execution has ended.

#--------*---------*---------*---------*---------*---------*---------*---------*
# Desc: Test B for reading a text file line-by-line into a list
#--------*---------*---------*---------*---------*---------*---------*---------*

import sys
import time

#                                  # MAINLINE
if __name__ == '__main__':
    print("OK, starting program...")

    inTextFile = '/Users/Mike/Desktop/garbage.txt'

#                                  # Test: B: using 'with'
    c=[]
    start_time = time.time()
    with open(inTextFile) as D: c = D.read().splitlines()
    print("--- %s seconds ---" % (time.time() - start_time))

    print("OK, program execution has ended.")
    sys.exit()                     # END MAINLINE

SALIDA:

OK, starting program...
--- 0.0020003318786621094 seconds ---
OK, program execution has ended.
CopyPasteIt
fuente