2011-02-16 9 views
7

Me gustaría saber por qué un objeto de archivo abierto utilizando la instrucción with() o en un bloque, permanece en el alcance después de la salida. ¿Los objetos '<' de archivo cerrado '>' se han limpiado alguna vez?¿Por qué el contexto se cuelga después de una declaración con?

>>> with open('test.txt','w') as f: 
...  f.write('test') 
... 
>>> f 
<closed file 'test.txt', mode 'w' at 0x00E014F0> 
>>> f.close() 


>>> if True: 
...  fal = open('demo.txt','w') 
...  fal.write('stuff') 
...  fal.close() 
... 
>>> fal 
<closed file 'demo.txt', mode 'w' at 0x00E015A0> 
+2

Aquí está [PEP 343] (http://www.python.org/dev/peps/pep-0343/) para leer un poco. –

Respuesta

14

en Python nuevos ámbitos (también conocido como espacios de nombres) son única creada por módulos, clases y funciones, pero no para cualquier otra declaración, especialmente no para with y if bloques. Los identificadores enlazados dentro del cuerpo de las declaraciones with o for están, por lo tanto, vinculados en el ámbito circundante más interno, que es el alcance de nivel superior del intérprete interactivo en su caso. Los identificadores están vinculados en un ámbito siempre que este alcance sea válido o hasta que se eliminen explícitamente del alcance (utilizando del como en del fal).

Los objetos solo se pueden limpiar cuando ya no se hace referencia a ellos. El momento real, en el que este objeto está realmente limpio, sin embargo no está definido. Python utiliza la recolección de elementos no utilizados para la administración de la memoria y no aplica una estrategia específica. En CPython, que utiliza el recuento de referencias, los objetos se limpian de inmediato, una vez que la última referencia queda fuera del alcance. Implementaciones alternativas como PyPy o Jython utilizan recolectores de basura más avanzados, que limpian objetos sin referencia en puntos de tiempo arbitrarios.

Esto significa, que en el ejemplo de los objetos unidos a f y fal se Bascially nunca se limpian, ya que el ámbito de nivel superior de la intérprete interactivo no existe de forma natural, siempre que el interpeter se está ejecutando. Sin embargo, tenga en cuenta que esto no es realmente un problema, ya que, sin embargo, están cerrados correctamente y ya no reclaman ningún recurso de archivo, sino solo algo de memoria.

+3

+1 Buena explicación del Python GC. – Aphex

+1

Gracias por la buena respuesta. – pyInTheSky

+0

Para ser claros, siguen consumiendo recursos, pero no el recurso de archivo. –

0

El objeto de archivo, como cualquier otro objeto, 'se pasea' por la duración de su programa, hasta que se borra (su método __del__ se llama).

del f hará que f sea basura recogida por el recolector de basura de Python. Esto sucede automáticamente cuando sale de un alcance, su script termina, o en su ejemplo, la sesión de intérprete finaliza.

+2

Esto es engañoso. Python eliminará el objeto cuando no haya más referencias, y 'del f' solo eliminará una referencia al objeto al que hace referencia' f'. – delnan

+0

Correcto, pero me refería a 'del f' como parte de su ejemplo, donde solo tiene una referencia (PODRÍA leer las complejidades del mecanismo de recuento de referencias del GC de pitón para una explicación más profunda). – Aphex

+0

Si ese es el caso, entonces, si el contenedor '__exit__' que forma parte de la sentencia with() llama a __del__, no entiendo cómo determinar el alcance de la variable dentro de la instrucción con, no hace que se elimine por completo. En mi ejemplo, no hubo más referencias a 'f'. Se declaró directamente dentro de la declaración 'with()' – pyInTheSky

4

El nombre permanecerá en el alcance hasta que salga del alcance.

Si desea que el objeto limpiado, asignar un valor diferente al nombre, al igual que

f = None 

Esto no cierra el archivo!

Es una buena costumbre limitar los ámbitos al estructurar el programa en funciones (y posiblemente clases). Eso lo hace más legible y hace que los objetos independientes (sin nombres en el alcance que se refieren al objeto) sean elegibles para la recolección de basura.

esto no suele ser un problema cuando se utiliza el símbolo aunque :)

+1

El archivo * está * cerrado. Incluso 'repr' te dice eso. Pero un archivo cerrado no elimina el identificador y mágicamente hace desaparecer todas las referencias. De lo contrario, es una buena respuesta y, de hecho, toca el problema del alcance, por lo que +1. – delnan

+0

@delnan en este caso es. Solo quería hacer explícito que un archivo que desaparece del contexto no necesariamente lo cierra. – extraneon

+0

Cuando se usa en un bloque 'with', * se * cerrará a menos que el intérprete falle. Pero sí, solo eliminar una referencia a ella generalmente no hará que se cierre. – delnan

0

with declaración de Python llama __exit__ método de la clase de archivos [el cual, en el caso de los archivos, los cierra]. No elimina el objeto; se limpia solo cuando lo limpia explícitamente o cierra el programa/intérprete.

+4

... que sería asincrónico con GC de todos modos. Para expandir, la variable aún está presente porque 'con' no introduce su propio alcance. – delnan

Cuestiones relacionadas