open() and EOFError

Steven D'Aprano steve+comp.lang.python at pearwood.info
Mon Jul 7 14:07:24 EDT 2014


On Mon, 07 Jul 2014 20:31:53 +0300, Marko Rauhamaa wrote:

> If the open() call is guarded against exceptions (as it usually should),
> one must revert to the classic syntax:
> 
>     try:
>          f = open(path)
>     except IOError:
>          ...
>     try:
>          ...
>     finally:
>          f.close()


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



While I agree with the general idea that try blocks should be as narrow 
*as reasonable*, they shouldn't be as narrow *as possible* since one can 
start guarding against unreasonable things.

try:
    open
except NameError:
    ...
else:
    try:
        f = open(filename)
    except ZeroDivisionError:
        # Just in case open has been monkey-patched.
        ...
    except NameError:
        # Oops! Forgot to bind a value to filename!
        # Or maybe another thread deleted open??? Woe, woe!!!
        ...


The thing is, even if you catch these bizarre things, what are you going 
to do with them? If you can't do anything about it, there's no point 
catching the exception -- never catch anything you can't recover from, or 
otherwise handle. Just treat it as a fatal error and let it cause a 
traceback.

As a general rule of thumb, if you have two things which (under 
reasonable circumstances) might fail in *different* ways, then it's okay 
to put them in the same try block, and then catch the two exceptions 
separately:

try:
    do_this(with_that())
except ThatError:
    ...
except ThisError:
    ...


If you handle the exceptions the same way, then you can still put them in 
the same try block:

try:
    do_this(with_that())
except (ThatError, ThisError):
    ...


The worst case is when they might fail with the same exception, but you 
need to handle the failures differently:

try:
    a = with_that()
except ThatError:
    ...
else:
    try:
        do_this(a)
    except ThatError:
        ...


That gets old really quickly! But then, handling errors is always the 
ugliest part of coding. Hiding the messy details inside a function is 
often a good idea.


-- 
Steven



More information about the Python-list mailing list