views:

921

answers:

4

I have the following code (adapted from an example given in Dive Into Python) that reads the entire contents of a file into a buffer.

buffer = ""

try:
    file = open(postFileName, 'rU')
    try:
        # Read the entire POST log file into a buffer
        buffer += file.read()
    finally:
        file.close()
except IOError:
    buffer += "The POST file could not be opened."

What's bothering me about this code is the inner try/finally block without an except block. Do I need an except block in there? Can the call to read() fail after the call to open() was successful? I know the try-except-finally is now unified, so adding one, at least syntactically, is not a problem.

If I add an except block, under what conditions will it be executed, and how do I write a test to make sure it runs under those conditions?

Additionally, if I don't need an except block, then why do I need the inner try/finally block at all?

A: 

With a recent version of Python, you don't need to nest try-except and try-finally. try-except-finally has been unified:

try:
  non_existing_var
except:
  print 'error'
finally:
  print 'finished'
Oli
Thanks, but I already knew about the try/except/finally syntax (I didn't know that they were once separate, actually). My problem is really about how to test the file.read() failure to make sure the except block runs under the right (wrong?) conditions.
Bill the Lizard
A: 

Googling a little bit got this Unified try/except/finally

Hope it helps ;)

dario minonne
Thanks, I'm such a Python newb that I didn't even know that they *weren't* unified at one time. My question is really about how to test the file.read() error, though.
Bill the Lizard
+4  A: 

I find that finally blocks are often overused. The file close (and a few other similar patterns) are so important that Python 3.0 will have a with statement just to cover this base in a slightly less obscure way.

  • Do I need an except with a finally?

    That hits on the confusing nature of this specific example, and why they added the with statement.

    The finally does "no matter what" cleanup. Exception or no exception, the finally is always executed.

  • Can the call to read() fail after the call to open() was successful?

    All OS calls, all I/O calls (almost everything) can raise an exception. All kinds of bad things can happen after open and before read.

  • If I add an except block, under what conditions will it be executed?

    Read up on files. There are lots of goofy I/O errors that can occur between open and read. Also, read up on the built-in exceptions. http://www.python.org/doc/2.5.2/lib/module-exceptions.html

  • How do I write a test to make sure it runs under those conditions?

    You'll need a mock file object. This object will responds to open but raises an IOError or OSError on every read.

  • If I don't need an except block, then why do I need the inner try/finally block at all?

    Cleanup. The finally will be executed no matter what exception is raised.

Try this. See what it does.

try:
 raise OSError("hi mom")
finally:
 print "Hmmm"
S.Lott
Thanks for hitting every part of my question. Very helpful.
Bill the Lizard
+2  A: 

I disagree with the other answers mentioning unifying the try / except / finally blocks. That would change the behaviour, as you wouldn't want the finally block to try to close the file if the open failed. The split blocks are correct here (though it may be better using the new "with open(filename,'rU') as f" syntax instead).

There are reasons the read() could fail. For instance the data could be too big to fit into memory, or the user may have signalled an interrupt with control-C. Those cases won't be caught by the IOError, but are left to be handled (or not) by the caller who may want to do different things depending on the nature of the application. However, the code does still have an obligation to clean up the file, even where it doesn't deal with the error, hence the finally without the except.

Brian
Thanks. Your explanation of how the read could fail after the file was successfully opened was helpful.
Bill the Lizard