¿Es explícitamente importante cerrar archivos?

149

En Python, si abre un archivo sin llamar close()o cierra el archivo pero no lo usa try, finallyo la " with" instrucción, ¿es un problema? ¿O es suficiente como práctica de codificación confiar en la recolección de basura de Python para cerrar todos los archivos? Por ejemplo, si uno hace esto:

for line in open("filename"):
    # ... do stuff ...

... ¿esto es un problema porque el archivo nunca se puede cerrar y podría producirse una excepción que impida su cierre? ¿O se cerrará definitivamente al final de la fordeclaración porque el archivo queda fuera de alcance?

usuario553702
fuente
13
El archivo no sale del alcance al final del forbloque. Su recuento de referencia irá a cero, haciendo que se cierre automáticamente, pero solo las funciones, clases y módulos definen ámbitos en Python, no otras declaraciones compuestas.
agf
18
No es un problema a menos que sea un problema. En el nivel del sistema operativo, los archivos abiertos por el script se cerrarán cuando el script finalice, por lo que no debe preocuparse por cerrar archivos en scripts de herramientas descartables. Sin embargo, los procesos tienen un límite en la cantidad de archivos abiertos que pueden mantener, por lo que es posible que las secuencias de comandos complejas o de larga duración tengan que ser más cuidadosas. En cualquier caso, es un buen hábito cerrar sus archivos.
Russell Borogove
3
@agf: Tiene razón en que el archivo no está fuera de alcance, pero no está relacionado con la distinción entre forbloques y funciones / clases / módulos. Es mucho más simple que eso: los objetos no tienen ámbitos, solo los nombres. No hay ningún nombre que se refiera a este objeto, por lo que no hay nada aquí para permanecer dentro o fuera del alcance.
máximo
@max Mi comentario está corrigiendo su suposición de que hay un alcance asociado con el forbucle y mencionando que el archivo se cierra por una razón completamente diferente. No entra en qué ámbitos hay en Python, ya que no es relevante aquí.
agf
@max hay una referencia implícita al alcance del bucle ... este es un argumento de semántica
Peter R

Respuestas:

126

En su ejemplo, no se garantiza que el archivo se cierre antes de que salga el intérprete. En las versiones actuales de CPython, el archivo se cerrará al final del ciclo for porque CPython usa el recuento de referencias como su mecanismo principal de recolección de basura, pero eso es un detalle de implementación, no una característica del lenguaje. No se garantiza que otras implementaciones de Python funcionen de esta manera. Por ejemplo, IronPython, PyPy y Jython no usan el recuento de referencias y, por lo tanto, no cerrarán el archivo al final del ciclo.

Es una mala práctica confiar en la implementación de recolección de basura de CPython porque hace que su código sea menos portátil. Es posible que no tenga pérdidas de recursos si usa CPython, pero si alguna vez cambia a una implementación de Python que no usa el conteo de referencias, deberá revisar todo su código y asegurarse de que todos sus archivos estén cerrados correctamente.

Para su ejemplo use:

with open("filename") as f:
     for line in f:
        # ... do stuff ...
Peter Graham
fuente
8
¿El uso with open() as fcierra automáticamente el archivo una vez hecho?
Rohan
24
@Rohan sí, esa es la pequeña magia que withproporciona la declaración, pero, por supuesto, para que esta magia funcione, el objeto debe tener los métodos especiales __enter__y __exit__, en este último, el objeto debe hacer closey cualquier otra cosa de limpieza que deba hacerse en el final de la withdeclaración ...
Copperfield
1
FYI: Esta respuesta solo explica "cuándo estaría cerrado", pero no explica "qué pasa si permanece abierto". Para este último, lea "¿Qué pasaría si un archivo permanece abierto?" parte de esta respuesta ( askubuntu.com/questions/701491/… )
RayLuo
Además, no cerrar archivos puede resultar en archivos truncados ya que el contenido del archivo no se ha vaciado.
Erwan Legrand
Entonces, si no cierro el archivo, ¿recuperaré mi memoria con seguridad una vez que el programa deje de ejecutarse? ¿O tengo que renunciar a todo el intérprete?
Pro Q
22

Algunas pitones cerrarán los archivos automáticamente cuando ya no estén referenciadas, mientras que otras no lo harán y depende de la O / S cerrar los archivos cuando salga el intérprete de Python.

Incluso para las pitones que cerrarán los archivos por usted, el tiempo no está garantizado: podría ser inmediatamente o podría ser segundos / minutos / horas / días más tarde.

Entonces, si bien es posible que no experimente problemas con el Python que está utilizando, definitivamente no es una buena práctica dejar sus archivos abiertos. De hecho, en cpython 3 ahora recibirá advertencias de que el sistema tuvo que cerrar los archivos por usted si no lo hizo.

Moraleja: Limpia después de ti. :)

Ethan Furman
fuente
9
Los archivos se cierran cuando ya no se hace referencia en CPython, pero esa no es una función de idioma. Si lo fuera, podría confiar en él.
Peter Graham
9

Aunque es bastante seguro usar tal construcción en este caso particular, existen algunas advertencias para generalizar dicha práctica:

  • potencialmente puede quedarse sin descriptores de archivo, aunque es poco probable, imagine cazar un error como ese
  • es posible que no pueda eliminar dicho archivo en algunos sistemas, por ejemplo, win32
  • si ejecuta algo que no sea CPython, no sabe cuándo se cierra el archivo
  • si abre el archivo en modo de escritura o lectura-escritura, no sabe cuándo se vacían los datos
Dima Tisnek
fuente
3

El archivo obtiene basura recolectada y, por lo tanto, cerrada. El GC determina cuándo se cierra, no tú. Obviamente, esta no es una práctica recomendada porque podría alcanzar el límite de manejo de archivo abierto si no cierra los archivos tan pronto como termine de usarlos. ¿Qué pasa si dentro de ese forciclo tuyo, abres más archivos y los dejas?

Nam Nguyen
fuente
Pero si abrió otros archivos dentro de ese ciclo for, aún sería el caso de que hubiera más de un archivo abierto simultáneamente, ya sea que cierre explícitamente alguno de ellos o no. ¿Está diciendo que el archivo no es necesariamente recolectado como basura tan pronto como el archivo sale del alcance, por lo tanto, se cerraría antes si se hiciera explícitamente? ¿Qué pasa cuando ocurre una excepción (cuando usas con / try-finally vs. no hacerlo)?
user553702
1
En CPython, el recuento de referencias hará que se recopile después de la fordeclaración; no tendrá que esperar a la próxima ejecución de recolección de basura.
agf
3

Hola, es muy importante cerrar el descriptor de tu archivo cuando vayas a usar su contenido en el mismo script de Python. Hoy mismo me doy cuenta después de tanto tiempo de depuración. La razón es que el contenido se editará / eliminará / guardará solo después de que cierre su descriptor de archivo y los cambios se vean afectados.

Supongamos que tiene una situación en la que escribe contenido en un nuevo archivo y luego, sin cerrar fd, está usando ese archivo (no fd) en otro comando de shell que lee su contenido. En esta situación, no obtendrá los contenidos para el comando de shell como se esperaba y si intenta depurar no puede encontrar el error fácilmente. También puede leer más en la entrada de mi blog http://magnificentzps.blogspot.in/2014/04/importance-of-closing-file-descriptor.html

Zeel Shah
fuente
1

Durante el proceso de E / S, los datos se almacenan en el búfer: esto significa que se guardan en una ubicación temporal antes de escribirse en el archivo.

Python no vacía el búfer, es decir, escribe datos en el archivo, hasta que esté seguro de que ha terminado de escribir. Una forma de hacerlo es cerrar el archivo.

Si escribe en un archivo sin cerrar, los datos no llegarán al archivo de destino.

Sanket Nagrale
fuente