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

V

Victor Hooi

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?)

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.

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, whenyou get your IOError, how do you distinguish where it came from? (e.g. If you wanted to print a friendly error message, saying "Error writing to filewhile feeding.", or if you otherwise wanted to handle it different).

Would I wrap all of the calls in a try-except block?

try:
my_pet.feed()
my_pet.shower()
except IOError as e:
# Do something to handle exception?

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

Cheers,
Victor
 
C

Chris Angelico

Would I wrap all of the calls in a try-except block?

try:
my_pet.feed()
my_pet.shower()
except IOError as e:
# Do something to handle exception?

It really depends more on how you go about recovering from errors. If
feeding the dog and showering the dog are completely independent, you
should catch errors for them separately (probably inside feed() and
shower()), but if a problem with feeding the dog stops you from
showering him, then do what you have here. Catch exceptions where it
makes sense to recover from the issue. Sometimes that means putting a
blanket catch-all at some point ("if anything goes wrong here, log the
error, return an HTTP 500, and go deal with the next query"), and
sometimes it means not catching errors at all (any that bubble all the
way up will get reported on STDERR, which is often the most useful
handling anyway).

ChrisA
 
S

Steven D'Aprano

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.
 
T

Terry Reedy

I have a general question regarding try-except handling in Python.

In Python, try-except can unapologetically be used as as alternate
conditional-execution control-flow construct.

if <condition>:
<do something>
else:
<do something else>

can often be re-written

try:
<do something>
except <exception indicating that condition was false>:
<so something else>

Some reasons for using the try_except form:
1. <condition> is volatile and may change between the 'if <condition>
check and the <do something> performance.
2. <condition> is expensive to check>.
3. <condition> is nearly always True (say >= 90% of the time).

Notice that 'except' is at least as close to 'try' as 'else' is to 'if'.

General rule: handle exceptions as soon as you can do something useful.

You can find lots of examples in the stdlib where <do something> is a
single simple statement.*** I recommend that beginners try reading some
of the stdlib code. It is not necessarily all great, but the average
quality should be pretty decent. Of course, some modules are more recent
than others.
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.

Do use with blocks.
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?)

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.

This was a side comment in a specific context of IOErrors that he thinks
are best handled later. Perhaps Bernd has seen some useless inner code
try-excepts that I have not.
From reading other posts, this seems to be the consensus as well.

As stated above, not among the people who develop Python.
However, how does this work if you have multiple methods which can
throw the same types of exceptions?

You have noticed the reason for the *** statement above ;-).
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? (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).

Would I wrap all of the calls in a try-except block?

try: my_pet.feed() my_pet.shower() except IOError as e: # Do
something to handle exception?

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).

See comment above about stdlib modules. Pick some that interest you.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,066
Latest member
VytoKetoReviews

Latest Threads

Top