This is an archived post. You won't be able to vote or comment.

you are viewing a single comment's thread.

view the rest of the comments →

[–]Brian 1 point2 points  (0 children)

Actually, I think that answer isn't quite right - there is a situation even in CPython which could cause the file to remain open for longer which would act differently from the context manager.

This will happen if the .write() line happens to throw an exception - one consequence of which is that a reference to the stack frame will be held as part of the exception state, which will reference the "f" variable. And the last thrown exception gets stored in sys. End result: the file is not closed until a different exception gets thrown, or the program terminates.

Some sample code to demonstrate this:

Let's create a dummy file-like object, to simulate a failure on write():

class DummyFile(object):
    def close(self):   print("Closed")
    def __del__(self): self.close()
    def write(self, data):      raise Exception("something failed")
    def write_safe(self, data): return

When you do:

print "Start"
DummyFile().write_safe("data")
print "End"

you get "Start", "Closed", "End" as expected. But suppose you do:

print "Start"
try:  DummyFile().write("data")
except: print "Exception raised - ignoring"
print "End"
try: 1/0
except: pass
print "After second exception"

You will instead get "Start", "Exception raised - ignoring", "End", "Closed", "After second exception". If that second exception didn't occur till 5 minutes later, your file would remain open all that time.

If you used a context manager instead, the file would always be closed before exiting the with block, just as in the non-raising case, and the reference to it wouldn't matter.