¿Los archivos se cierran durante una salida de excepción?


¿Los archivos abiertos (y otros recursos) se cierran automáticamente cuando el script sale debido a una excepción?

Me pregunto si necesito cerrar mis recursos durante mi manejo de excepciones.

**EDITAR: para ser más específico, estoy creando un archivo de registro simple en mi script. Quiero saber si debo preocuparme por cerrar el archivo de registro explícitamente en el caso de excepciones. dado que mi script tiene un complejo, anidado, try / excepto bloques, hacerlo es algo complicado, así que si python, CLIB, o el sistema operativo va a cerrar mi archivo de texto cuando el script se bloquea / errores, no quiero perder demasiado tiempo en asegurarse de que el archivo se cierra.

Si hay una parte en el manual de Python que habla de esto, por favor refiérame a ella, pero no pude encontrarla.

 23
Author: Ashwini Chaudhary, 2013-07-10

4 answers

No, no lo hacen.

Use la instrucción with si desea que sus archivos se cierren incluso si se produce una excepción.

De los documentos :

La instrucción with se usa para envolver la ejecución de un bloque con métodos definidos por un administrador de contexto. Esto permite común pruebe...excepto...finalmente patrones de uso a encapsular para una reutilización conveniente.

De docs:

La instrucción with permite que objetos como archivos ser utilizado de una manera que asegura que siempre están limpian rápidamente y correctamente.

with open("myfile.txt") as f:
    for line in f:
        print line,

Después de que se ejecuta la instrucción, el archivo f siempre se cierra, incluso si se encontró un problema durante el procesamiento de las líneas. Otros objetos que proporcionan acciones de limpieza predefinidas indicarán esto en su documentación.

 23
Author: Ashwini Chaudhary,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-07-10 18:19:44

Una pregunta bastante sencilla.

Dos respuestas.

Uno diciendo: "Sí."

El otro diciendo: "¡No!"

Ambos con votos positivos significativos.

A Quién creer? Permítanme que lo aclare.


Ambas respuestas tienen algo de verdad, y depende de lo que quieres decir con un archivo cerrado.

Primero, considere lo que se entiende por cerrar un archivo desde el sistema operativo perspectiva.

Cuando un proceso sale, el sistema operativo borra todos los recursos que solo ese proceso tenía abierto . Programas de otro modo mal comportados que crash pero no liberó sus recursos podría consumir todo el sistema recurso.

Si Python fue el único proceso que tenía ese archivo abierto, entonces el archivo cierra. Del mismo modo, el sistema operativo limpiará la memoria asignada por el proceso, los puertos de red que aún estaban abiertos, y la mayoría de los otros cosa. Hay algunas funciones excepcionales como shmat que crear objetos que persisten más allá del proceso, pero en su mayor parte el sistema operativo se encarga de todo.

Ahora, ¿qué pasa con el cierre de archivos desde la perspectiva de Python? Si algún programa escrito en cualquier lenguaje de programación sale, la mayoría de los recursos se limpian up-pero, ¿cómo maneja Python la limpieza dentro de programas Python estándar?

La implementación estándar de CPython de Python-a diferencia de otros Python implementaciones como Jython-uses cuenta de referencia para hacer la mayor parte de su recolección de basura. Un objeto tiene un campo de recuento de referencia. Cada vez algo en Python obtiene una referencia a algún otro objeto, la referencia el campo count en el objeto referido se incrementa. Cuando una referencia es perdido, por ejemplo, porque una variable ya no está en el ámbito, el recuento de referencia es decrementar. Cuando el recuento de referencias llega a cero, ningún código Python puede alcanzar el objeto ya no, por lo que el objeto queda desasignado. Y cuando se pone desasignado, Python llama al __del__() destructor .

El método de Python __del__() para archivos limpia los búferes y cierra el archivo desde el punto de vista del sistema operativo. Debido a la referencia contando, en CPython, si abre un archivo en una función y no devuelve el archivo objeto, a continuación, el recuento de referencia en el archivo se reduce a cero cuando la función sale, y el archivo se vacía y se cierra automáticamente. Cuando el programa termina, CPython desreferencias todos los objetos, y todos los objetos tienen sus destructores llamado, incluso si el programa termina debido a un salvedad. (Esto falla técnicamente para el caso patológico donde tiene un ciclo de objetos con destructores, al menos en versiones de Python anteriores a 3.4.)

Pero eso es solo la implementación de CPython. Python el lenguaje está definido en la referencia del lenguaje Python , que es lo que todos los Python se requiere que las implementaciones sigan para llamarse a sí mismas Compatible con Python.

El language reference explica la gestión de recursos en su modelo de datos sección:

Algunos objetos contienen referencias a recursos "externos" como open archivos o windows. Se entiende que estos recursos se liberan cuando el objeto es basura-recogido, pero puesto que la recolección de basura no es garantizado para suceder, tales objetos también proporcionan una manera explícita de libera el recurso externo, normalmente un método close (). Los programas son muy recomendable cerrar explícitamente tales objetos. El ‘tratar...finalmente 'declaración y la' con ' declaración proporcionan conveniente maneras de hacer esto.

Es decir, CPython generalmente cerrará inmediatamente el objeto, pero eso puede cambio en una versión futura, y otras implementaciones de Python ni siquiera son necesario para cerrar el objeto en absoluto.

Entonces, por portabilidad y porque explícito es mejor que implícito, es muy recomendable llamar close() en todo lo que puede ser close() d, y haga eso en un bloque finally si hay código entre la creación del objeto y close() que podría generar una excepción. O para usar el azúcar sintáctico with que logra lo mismo. Si lo haces que, a continuación, los búferes en los archivos se vaciarán, incluso si una excepción es elevado.

Sin embargo, incluso con la declaración with, los mismos mecanismos subyacentes son en el trabajo. Si el programa se bloquea de una manera que no da Python __del__() método una oportunidad de ejecutar, todavía puede terminar con un corrupto archivo en disk:

#!/usr/bin/env python3.3

import ctypes

# Cast the memory adress 0x0001 to the C function int f()
prototype = ctypes.CFUNCTYPE(int)
f = prototype(1)

with open('foo.txt', 'w'):
    x.write('hi')
    # Segfault
    print(f())

Este programa produce un archivo de longitud cero. Es un caso anormal, pero muestra que incluso con la instrucción with los recursos no siempre necesariamente ser limpiado de la manera que usted espera. Python le dice a la operación sistema para abrir un archivo para escritura, que lo crea en disco; Python escribe hi en los búferes stdio de la biblioteca C; y luego se bloquea antes del with declaración termina, y debido a la corrupción aparente memoria, no es seguro para que el sistema operativo intente leer los restos del búfer y descargarlos al disco. Así que el programa no puede limpiar correctamente a pesar de que hay una instrucción with. Ups. A pesar de esto, close() y with casi siempre funcionan, y su programa siempre es mejor tenerlos que no tenerlos.

Así que la respuesta no es ni sí ni no. La declaración with y close() técnicamente no son necesario para la mayoría de los programas ordinarios de CPython. Pero no usarlos resulta en código no portátil que se verá mal. Y mientras son extremadamente{[81]]} útil, todavía es posible que fallen en casos patológicos.

 19
Author: andrewdotn,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-08-04 20:13:41

Sí lo hacen.

Esto es un CLIB (al menos en cpython) y cosa del sistema operativo. Cuando el script salga, CLIB limpiará y cerrará todos los objetos de archivo. Incluso si no lo hace (por ejemplo, Python se bloquea), el sistema operativo cierra sus recursos al igual que cualquier otro proceso. No importa si fue una excepción o una salida normal o incluso si su python o cualquier otro programa.

Aquí hay un script que escribe un archivo y genera una excepción antes de que el contenido del archivo haya sido arrojado al disco. Funciona bien:

~/tmp/so$ cat xyz.txt
cat: xyz.txt: No such file or directory
~/tmp/so$ cat exits.py
f = open("xyz.txt", "w")
f.write("hello")
print("file is", open("xyz.txt").read())
assert False

~/tmp/so$ python exits.py
('file is', '')
Traceback (most recent call last):
  File "exits.py", line 4, in <module>
    assert False
AssertionError
~/tmp/so$ cat xyz.txt
hello
 3
Author: tdelaney,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-07-10 18:20:15

Yo, al igual que otras personas en este hilo, me quedo con la pregunta, "Bueno, ¿qué es finalmente cierto?"

Ahora, suponiendo que los archivos se dejan abiertos en una terminación prematura del programa -- y hay muchos casos de este tipo además de excepciones debido al manejo de archivos the la única forma segura de evitar esto, es leer todo (o parte del) archivo en un búfer y cerrarlo. Luego maneje el contenido en el búfer según sea necesario. Esto es esp. el caso de búsqueda global, cambios, etc. que tienen que se hará en el archivo. Después de hacer los cambios, uno puede escribir todo el búfer en el mismo u otro archivo a la vez, evitando el riesgo de dejar abierto el archivo recién creado doing haciendo muchas lecturas y escritos!que es el peor de todos!

 0
Author: Apostolos,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-01-14 12:55:15