La forma más fácil de leer / escribir el contenido de un archivo en Python

82

En Ruby puedes leer desde un archivo usando s = File.read(filename). El más corto y claro que conozco en Python es

with open(filename) as f:
    s = f.read()

¿Hay alguna otra forma de hacerlo que lo haga aún más corto (preferiblemente una línea) y más legible?

Nota: inicialmente formulé la pregunta como "hacer esto en una sola línea de código". Como señaló S.Lott, más corto no significa necesariamente más legible. Así que reformulé mi pregunta solo para aclarar lo que quería decir. Creo que el código Ruby es mejor y más legible no necesariamente porque es una línea frente a dos (aunque eso también importa), sino también porque es un método de clase en lugar de un método de instancia, que no plantea dudas sobre quién cierra el archivo, cómo asegurarse de que se cierre incluso si se genera una excepción, etc. Como se señala en las respuestas a continuación, puede confiar en el GC para cerrar su archivo (lo que lo convierte en una sola línea), pero eso empeora el código incluso aunque es más corto. No solo por ser intransitable, sino por dejarlo claro.

ibz
fuente
7
Crea tu propia función. Entonces puedes usarlo para obtener el contenido. La llamada sería de una línea.
Felix Kling
1
Solo por curiosidad, ¿la declaración de Ruby también cierra el archivo?
dheerosaur
8
-1: Nadie gana en code golf.
S.Lott
3
Mi pregunta tiene sentido para mí. Estoy tratando de encontrar una mejor manera de escribir estas dos líneas (4 líneas antes de la withdeclaración en 2.5). Quizás haya una manera, quizás no la haya. Siempre puedo intentar averiguarlo, ¿verdad? Si no te gusta, vota en contra y sigue adelante. :)
ibz
1
El beneficio de File.readlines("filename")es que lee el contenido de un archivo dado su nombre. No hay ningún identificador de archivo, descriptor u objeto en ninguna parte como evidencia. Todos los "equivalentes" de Python que he visto incluyen una apertura / cierre explícito (o peor, una apertura implícita que requiere un cierre explícito).
Mark Reed

Respuestas:

11

Si está dispuesto a usar bibliotecas, intente instalar bifurcación-ruta (con easy_install o pip).

Entonces puedes hacer:

from path import path
s = path(filename).bytes()

Esta biblioteca es bastante nueva, pero es una bifurcación de una biblioteca que ha estado flotando alrededor de Python durante años y se ha utilizado bastante. Desde que encontré esta biblioteca hace años, casi nunca uso os.patho open()más.

zapato
fuente
Parece una bonita biblioteca. No lo instalaré solo por esto, pero lo tendré en cuenta.
ibz
1
¡No entiendo por qué esta fue la respuesta aceptada, ya que es un truco total!
Nikolay
La ruta bifurcada v0.2.3 instalada por pip 18.6 en Windows no es compatible con Python 3.6.4. Parece que el formato utilizado para las constantes octales (por ejemplo, en 0777lugar de 0o0777) no es compatible con mi versión actual de Python.
Christoffer Soop
+1 a la respuesta de Eyal Levin . Si pathlib o pathlib2 hubiera existido cuando respondí originalmente esto hace 8 años, los habría mencionado en lugar de bifurcar-path. No he usado el camino bifurcado en años.
zapato de presión
149
with open('x.py') as f: s = f.read()

*** sonríe ***

Mark Tolonen
fuente
1
Simplemente no hay razón para no escribirlo como OP lo hizo originalmente. La intención era clara.
Mark Tolonen
43

Esto es igual que el anterior pero no maneja errores:

s = open(filename, 'r').read()
pyfunc
fuente
21
En realidad no, el tuyo deja el archivo abierto.
ibz
3
La implementación de CPython cierra el archivo cuando el recuento de referencias llega a cero, pero ese es un detalle de implementación en el que no se debe confiar.
Mark Tolonen
1
Esto maneja errores; se lanzará una excepción como de costumbre. Esto no "deja el archivo abierto", pero lo que puede hacer es retrasar el cierre del archivo dependiendo de la implementación de GC. Eso puede ser un problema (bloquear en Windows y, por ejemplo, límites de FD si se desplaza sobre muchos archivos), pero eso es muy diferente de dejar el archivo abierto (por ejemplo, filtrar el archivo).
Glenn Maynard
11
Si su objetivo de diseño es "una línea de código", ha inhalado demasiado Perl y necesita programar un tiempo serio para no lavarse el cerebro.
Glenn Maynard
6
No, esto no es confuso en lo más mínimo.
Glenn Maynard
36

Utilice pathlib .

Python 3.5 y superior:

from pathlib import Path
contents = Path(file_path).read_text()

Para versiones inferiores de Python, use pathlib2 :

$ pip install pathlib2

Entonces

from pathlib2 import Path
contents = Path(file_path).read_text()

Escribir es igual de fácil:

Path(file_path).write_text('my text')
Eyal Levin
fuente
18
contents = open(filename).read()
ars
fuente
9
¿Y cuándo cierras el archivo?
ibz
1
@ionut bizau - Cuando el retorno de la open(...)basura se recolecta, creo. Que alguien me corrija si me equivoco.
detly
1
Esta es la forma más corta de hacerlo. No sé por qué no tiene votos.
Pritesh Acharya
10

Esto no es Perl; no desea forzar el ajuste de varias líneas de código en una sola línea. Escribir una función, luego llamar a la función toma una línea de código.

def read_file(fn):
    """
    >>> import os
    >>> fn = "/tmp/testfile.%i" % os.getpid()
    >>> open(fn, "w+").write("testing")
    >>> read_file(fn)
    'testing'
    >>> os.unlink(fn)
    >>> read_file("/nonexistant")
    Traceback (most recent call last):
        ...
    IOError: [Errno 2] No such file or directory: '/nonexistant'
    """
    with open(fn) as f:
        return f.read()

if __name__ == "__main__":
    import doctest
    doctest.testmod()
Glenn Maynard
fuente
5

Lento, feo, específico de la plataforma ... pero de una sola línea ;-)

import subprocess

contents = subprocess.Popen('cat %s' % filename, shell = True, stdout = subprocess.PIPE).communicate()[0]
eumiro
fuente
3
aaaaaaaaaaargh! (exceso de 'a's para cumplir con el límite mínimo de caracteres)
Peter Gibson
5
Ciertamente coincide con el espíritu de la pregunta ... el uso perverso de Python para que se parezca a Bash no es peor que hacer que se parezca a Ruby o Perl.
2010
3

Tan simple como eso:

    f=open('myfile.txt')
    s=f.read()
    f.close()

Y haz lo que quieras con el contenido "s"

PYK
fuente
-1
contents = open(filename)

Esto le da un generador, por lo que debe guardar los valores en algún lugar, o

contents = [line for line in open(filename)]

Esto hace que el ahorro en la lista de cierre explícito no sea posible (al menos con mi conocimiento de Python).

Tony Veijalainen
fuente
1
y con contenido = '' .join (línea por línea en abrir (nombre de archivo)) tiene el contenido del archivo original ...
eumiro
El uso de un archivo como iterador no cierra el archivo de forma determinista (como withhace). No puede, porque una vez finalizada la iteración, sigue siendo válido buscar el archivo y comenzar a leer de nuevo, lo que no funcionaría si la iteración cerrara el archivo.
Glenn Maynard
@Glenn Pero si usa el generador en la comprensión de listas como mi ejemplo, ni siquiera es posible cerrarlo porque no tiene nombre.
Tony Veijalainen
"No poder cerrarlo" no es lo mismo que "no es necesario cerrarlo".
Glenn Maynard
Tal vez sea así, pero no sabría cómo acceder a ese identificador de archivo desde la comprensión de la lista interna. ¿Debería ser tal vez el comando 'finalizar todas las e / s de archivos, cerrar todos los archivos abiertos del programa' en Python? ¿O tal vez gc explícito para objetos de archivo sería suficiente? El identificador de archivo está fuera de alcance, ya que la comprensión de la lista es un alcance separado.
Tony Veijalainen