5

I have a class where I create a file object in the constructor. This class also implements a finish() method as part of its interface and in this method I close the file object. The problem is that if I get an exception before this point, the file will not be closed. The class in question has a number of other methods that use the file object. Do I need to wrap all of these in a try finally clause or is there a better approach?

Thanks,

Barry

Baz
  • 12,713
  • 38
  • 145
  • 268
  • This is basically the reason try... finally was created. – Oliver Oct 25 '11 at 12:04
  • Yes, you will need to wrap it in a try clause. But you have mentioned that there are other methods that refer the same object, can you please elaborate ? – unni Oct 25 '11 at 12:05

3 Answers3

11

You could make your class a context-manager, and then wrap object creation and use of that class in a with-statement. See PEP 343 for details.

To make your class a context-manager, it has to implement the methods __enter__() and __exit__(). __enter__() is called when you enter the with-statement, and __exit__() is guaranteed to be called when you leave it, no matter how.

You could then use your class like this:

with MyClass() as foo:
    # use foo here

If you acquire your resources in the constructor, you can make __enter__() simply return self without doing anything. __exit__() should just call your finish()-method.

agf
  • 171,228
  • 44
  • 289
  • 238
Björn Pollex
  • 75,346
  • 28
  • 201
  • 283
  • 1
    +1 And there's [`contextlib.contextmanager`](http://docs.python.org/library/contextlib.html#contextlib.contextmanager) for making context managers off things that don't warrant an extra class otherwise. (I have to nitpick though: The `do` is not needed - read: a syntax error) –  Oct 25 '11 at 12:28
  • 2
    @delnan Or just call `file_handle.close()` in a `close` instance method and use `contextlib.closing`. (`do` removed) – agf Oct 25 '11 at 12:34
  • Yes, that's another option - though it's uglier at use site, especially since it requires importing `contextlib` everywhere. I didn't mean to suggest `contextlib.contextmanager` for this specific example, I just thought it would be useful to mention, since there are cases wheth the other approaches don't work so cleanly. –  Oct 25 '11 at 12:37
3

For short lived file objects, a try/finally pair or the more succinct with-statement is recommended as a clean way to make sure the files are flushed and the related resources are released.

For long lived file objects, you can register with atexit() for an explicit close or just rely on the interpreter cleaning up before it exits.

At the interactive prompt, most people don't bother for simple experiments where there isn't much of a downside to leaving files unclosed or relying on refcounting or GC to close for you.

Closing your files is considered good technique. In reality though, not explicitly closing files rarely has any noticeable effects.

Raymond Hettinger
  • 216,523
  • 63
  • 388
  • 485
  • Raymond - what about closing files opened for writing? I suppose flushing isn't guaranteed for each write, until the file has been closed? If a class's responsibility is to write into a file, which will then be read by some other entity (within the runtime of the process), it's probably important to guarantee the file gets closed – Eli Bendersky Oct 25 '11 at 12:26
  • 1
    Closing is more important for writes than reads, if only to flush the buffers. That being said, it's not like a puppy dies every time you forget to close a file ;-) Many short-lived scripts work fine with the interpreter closing everything before it exits -- good technique is to close but don't worry about it to much much -- it isn't a cardinal sin. – Raymond Hettinger Oct 25 '11 at 13:14
1

You can either have a try...finally pair, or make your class a context manager suitable for use in the with statement.

Eli Bendersky
  • 263,248
  • 89
  • 350
  • 412