views:

163

answers:

4

Hi all,

I find I've been confused by the problem that when I needn't to use try..except.For last few days it was used in almost every function I defined which I think maybe a bad practice.For example:

class mongodb(object):

    def getRecords(self,tname,conditions=''):
        try:
            col = eval("self.db.%s" %tname)
            recs = col.find(condition)
            return recs
        except Exception,e:
            #here make some error log with e.message

What I thought is ,exceptions may be raised everywhere and I have to use try to get them. And my question is,is it a good practice to use it everywhere when defining functions?If not are there any principles for it?Help would be appreciated!

Regards

+5  A: 

This (catching all possible exceptions very broadly) is indeed considered bad practice. You'll mask the real reason for the exception.

Catch only 'explicitely named' types of exceptions (which you expect to happen and you can/will handle gracefully). Let the rest (unexpected ones) bubble as they should.

You can log these (uncaught) exceptions (globally) by overriding sys.excepthook:

import sys
import traceback
# ...

def my_uncaught_exception_hook(exc_type, exc_value, exc_traceback):
    msg_exc = "".join( \
              traceback.format_exception(exc_type, exc_value, exc_traceback) )
    # ... log here...

sys.excepthook = my_uncaught_exception_hook # our uncaught exception hook
ChristopheD
+5  A: 

That may not be the best thing to do. Whole point of exceptions is that you can catch them on very different level than it's raised. It's best to handle them in the place where you have enough information to make something useful with them (that is very application and context dependent).

For example code below can throw IOError("[Errno 2] No such file or directory"):

def read_data(filename):
    return open(filename).read()

In that function you don't have enough information to do something with it, but in place where you actually using this function, in case of such exception, you may decide to try different filename or display error to the user, or something else:

try:
    data = read_data('data-file.txt')
except IOError:
    data = read_data('another-data-file.txt')
    # or
    show_error_message("Data file was not found.")
    # or something else
Łukasz
+2  A: 

You must find a balance between several goals:

  1. An application should recover from as many errors as possible by itself.

  2. An application should report all unrecoverable errors with enough detail to fix the cause of the problem.

  3. Errors can happen everywhere but you don't want to pollute your code with all the error handling code.

  4. Applications shouldn't crash

To solve #3, you can use an exception hook. All unhandled exceptions will cause the current transaction to abort. Catch them at the highest level, roll back the transaction (so the database doesn't become inconsistent) and either throw them again or swallow them (so the app doesn't crash). You should use decorators for this. This solves #4 and #1.

The solution for #2 is experience. You will learn with time what information you need to solve problems. The hard part is to still have the information when an error happens. One solution is to add debug logging calls in the low level methods.

Another solution is a dictionary per thread in which you can store some bits and which you dump when an error happens.

Aaron Digulla
+1  A: 

another option is to wrap a large section of code in a try: except: (for instance in a web application, one specific GUI page) and then use sys.exc_info() to print out the error and also the stack where it occurred

import sys
import traceback
try:
    #some buggy code    
    x = ??
except:
    print sys.exc_info()[0] #prints the exception class
    print sys.exc_info()[1] #prints the error message
    print repr(traceback.format_tb(sys.exc_info()[2])) #prints the stack
JiminyCricket