error handling when opening files

Steven D'Aprano steve at pearwood.info
Tue Jul 8 05:00:46 EDT 2014


On Tue, 08 Jul 2014 01:49:58 +0200, Alex Burke wrote:

> Hi there,
> 
> While reading up on a previous thread 'open() and EOFError' I saw the
> following (with minor changes to help make my question clearer) block
> suggested as a canonical way to open files and do something:

Emphasis on "a" canonical way, out of many canonical ways ;-)

> try:
>     f = open(path)
> except IOError:
>     handle_error()
> else:
>     with f:
>         do_stuff()

I wrote it that way to show that there is no need to fall back on the old-
fashioned "try...except...finally" idiom that was used before the with 
statement and context managers. In practice, I would usually do what you 
do:

> This somewhat surprised me because I'd always written such a block
> something more as follows:
> 
> try:
>     with open(path) as f:
>         do_stuff()
> except IOError:
>     handle_error('file never opened')
> except ApplicationError:
>     handle_error('doing something with the content went wrong')

assuming that open() and do_stuff() don't raise the same exceptions. If 
they do raise the same exceptions, and it is important to distinguish 
IOError raised by open() from IOError raised by do_stuff, then you cannot 
use this idiom.


> Aside from the pythonic but less widely known else clause of the
> try/except in the first form, what else is different? What nuances am I
> missing?
> 
> The reason I preferred the second was in addition to catching the
> IOError when attempting the open() if the file does not exist I thought
> I was accounting for the possibility en error occurs while reading data
> out of the file. That and to handle if do_stuff() was actually calling
> readline() or such on the file which I thought was possible source of
> issues.

Correct. But now imagine you're happily reading through the file, 
processing line after line, and halfway through the file read() fails 
because it's on a network share and somebody just tripped over the cable. 
Your script now *lies to you* and says the file was never opened.

If you care about accurate error messages, you should be more careful 
about conflating two different errors (that is, catching too much in a 
single try...except block).


> I am wondering if this is also related to some misunderstanding around
> the file context manager - on exit of the with() block a close is
> arranged, but if that close() is called in an error situation I was
> under the impression that the error would be raised again outside it.

In general, context managers may choose whether or not to re-raise 
exceptions. Some exceptions are not errors and may be swallowed silently. 
However, file objects will re-raise the error.

Interestingly, did you know that even *closing* a file can fail?


-- 
Steven



More information about the Python-list mailing list