File not closed on exception

Gabriel Genellina gagsl-py2 at yahoo.com.ar
Mon Oct 19 17:56:04 CEST 2009


En Mon, 19 Oct 2009 09:45:49 -0200, arve.knudsen at gmail.com  
<arve.knudsen at gmail.com> escribió:

> I thought that file objects were supposed to be garbage-collected and
> automatically closed once they go out of scope, at least that's what
> I've been told by more merited Python programmers.

An object (any object) is destroyed as soon as the last reference to the  
it is removed. A local variable holds a reference to the file object; it  
that is the ONLY reference, the file object will be destroyed when the  
variable goes out of scope, yes.
Note that:
- there might be more references to the object
- garbage collection is a separate subject; objects are reference-counted,  
zero=>kaputt, the GC has no say on this. GC is only used to break cycles  
(a->b, b->a) that would prevent the objects to reach 0 references.
- this behavior is specific of CPython

> I'm also quite sure
> that this is quite a common assumption in various programs, at least
> given what opensource code I've seen in my time.

When an object holds references to external resources that must be freed,  
this is not a good idea. Being explicit with the resource deallocation is  
much better than relying on object destruction sometime in the future...

> However, the
> following script doesn't work on Windows, since the file is still open
> when I try to remove it:
>
> import os.path
>
> def create():
>     f = file("tmp", "w")
>     raise Exception
>
> try: create()
> finally:
>     os.remove("tmp")
>
>
> So, what's the deal exactly, is the file supposed to be garbage-
> collected (and closed) at the end of create?

The object does not go out of scope because there is an additional  
reference: the exception traceback  holds a reference to all execution  
frames, and each frame holds a reference to its local variables.  So "f"  
is still alive. This is quite good for a debugger, or for logging  
purposes, as one can inspect the values of each and every variable along  
the frame chain. But until exception processing is finished, the "f"  
variable is alive and the "tmp" file is open.

How to deal with this depends on your use case. I don't know what can I  
modify on your small example and still being representative of your actual  
problem. The reccomended way to process a file uses a with statement:

def create():
     with open("tmp", "w") as f:
        # do something with the file
        raise Exception

This way the file is closed when leaving the with statement (either  
normally or because of an exception). And, if the file doesn't exist or  
access is denied, the open() call doesn't success either. In any case, it  
never remains open.

-- 
Gabriel Genellina




More information about the Python-list mailing list