Where to handle try-except - close to the statement, or in outer loop?

Steven D'Aprano steve+comp.lang.python at pearwood.info
Mon Nov 11 21:03:16 EST 2013


On Mon, 11 Nov 2013 17:34:21 -0800, Victor Hooi wrote:

> Hi,
> 
> I have a general question regarding try-except handling in Python.
> 
> Previously, I was putting the try-handle blocks quite close to where the
> errors occured:
> 
> A somewhat contrived example:
> 
>     if __name__ == "__main__":
>         my_pet = Dog('spot', 5, 'brown')
>         my_pet.feed()
>         my_pet.shower()
> 
> and then, in each of the methods (feed(), shower()), I'd open up files,
> open database connections etc.
> 
> And I'd wrap each statement there in it's own individual try-except
> block. (I'm guessing I should wrap the whole lot in a single try-except,
> and handle each exception there?)

Your description is ambiguous. Do you mean you have:

if __name__ == "__main__":
    try:
        my_pet = Dog('spot', 5, 'brown')
    except Whatever:
        pass
    try:
        my_pet.feed()
    except Whatever:
        pass
    try:
        my_pet.shower()
    except Whatever:
        pass

or that each individual method has it's own try...except block?

The first is certainly not good. If the call to Dog fails, you shouldn't 
proceed with the following lines, they certainly cannot succeed. On the 
other hand, if the call to my_pet.feed() fails (perhaps Spot is not 
hungry), then it is perfectly acceptable to ignore the exception and give 
Spot a bath regardless. So it depends on the circumstances.

On the other hand:

if __name__ == "__main__":
    try:
        my_pet = Dog('spot', 5, 'brown')
        my_pet.feed()
        my_pet.shower()
    except Whatever:
        pass

is too much, since an error in feeding the dog prevents you from showing 
the dog.


> However, the author here:
> 
> http://stackoverflow.com/a/3644618/139137
> 
> suggests that it's a bad habit to catch an exception as early as
> possible, and you should handle it at an outer level.

Since the poster doesn't give an actual example of this, it is hard to 
tell what he considers too early or too late. But in general, one should 
only catch exceptions that you can do something about, as soon as you can 
do something about it. Depending on what you can do to recover from an 
error, that may mean wrapping each statement in it's own try block, or 
(more rarely, in my experience) a whole bunch of statements.


> From reading other posts, this seems to be the consensus as well.
> 
> However, how does this work if you have multiple methods which can throw
> the same types of exceptions?
> 
> For example, if both feed() and shower() above need to write to files,
> when you get your IOError, how do you distinguish where it came from?

You can't, at least not easily and/or portably.


> (e.g. If you wanted to print a friendly error message, saying "Error
> writing to file while feeding.", or if you otherwise wanted to handle it
> different).

If your only reason for catching the error is to suppress the stack trace 
and provide a "friendly" (i.e. useless) error message, then don't use 
try...except at all. Instead, install a customer error handler:

http://docs.python.org/2/library/sys.html#sys.excepthook


Otherwise, you should only catch exceptions that you can do something 
about. That might mean retrying the operation:

while True:
    try:
        dog.feed()
    except DogNotHungryError:
        time.sleep(60*60)
        continue
    break


or ignoring the failure:

try:
    dog.feed()
except DogNotHungryError:
    pass
dog.bath()


or doing something else. If you can't do anything about the error, then 
you shouldn't catch it, and leave it to code higher up to deal with it.


> Can anybody recommend any good examples that show current best practices
> for exception handling, for programs with moderate complexity? (i.e.
> anything more than the examples in the tutorial, basically).

Yes. Read the code in the Python standard library! Open your text editor, 
if possible set it to open files in read-only mode, and browse the 
standard library.



-- 
Steven



More information about the Python-list mailing list