Question

I've created a bunch of functions and I need very similar except clauses in all of them, but I hate having so many lines of try and except clauses and the same code inside of each function. For example:

import sys
import random

def foo():
    num=random.random()
    try:
        if num>0.5: print 'OK'
        elif num>0.25: raise NameError('Too Small')
        else: raise KeyboardInterrupt
    except NameError:
        print "%s had a NameError" % sys._getframe().f_code.co_name
    except:
        print "%s had a different Error" % sys._getframe().f_code.co_name

def bar():
    num=random.random()
    try:
        if num>0.8: print 'OK'
        elif num>0.6: raise NameError('Too Small')
        else: raise KeyboardInterrupt
    except NameError:
        print "%s had a NameError" % sys._getframe().f_code.co_name
    except:
        print "%s had a different Error" % sys._getframe().f_code.co_name

The code after "try" is different for the functions, but the code after "except" is the same. I want to consolidate those except statements so they don't make my code look so cramped. Is there a good way to do this?

Was it helpful?

Solution

Python Decorators are what you want.

You said the except block is always the same. Make a custom decorator that does what you want. You'll have to apply this to each function/method but it sure does save duplication.

def handleError(function):
    def handleProblems():
        try:
            function()
        except Exception:
            print "Oh noes"
    return handleProblems


@handleError
def example():
   raise Exception("Boom!")

When calling a method with the decorator applied:

>>> 
>>> example()
Oh noes
>>> 

You will need to change the exception types as well as what you do, but you get the jist of where I'm going with this.

OTHER TIPS

The content inside your try block is the interesting stuff, so that should be in functions. Then just select which function you want, and call it, wrapped by your exceptions. You could even write the exception code as a function, and pass the selected function to this as an argument. e.g.

def foo():
    num=random.random()
    if num>0.5: print 'OK'
    elif num>0.25: raise NameError('Too Small')
    else: raise KeyboardInterrupt

def bar():
    num=random.random()
    if num>0.8: print 'OK'
    elif num>0.6: raise NameError('Too Small')
    else: raise KeyboardInterrupt

def try_numerics(f):
    try:
        f()
    except NameError:
        print "%s had a NameError" % sys._getframe().f_code.co_name
    except:
        print "%s had a different Error" % sys._getframe().f_code.co_name

# In your main code...
if (need_to_run_foo):
    try_numerics(foo)
elif (need_to_run_bar):
    try_numerics(bar)

The answer above does not apply for Functions that take arguments - for the later case, I think you would want something like this:

def handleError(f):
    def handleProblems(*args, **kwargs):
        try:
            return f(*args, **kwargs)
        except Exception:
            print "Oh noes"
    return handleProblems

We can test it like so:

@handleError
def addTwo(x, y): 
    print(x + y) 

>>> addTwo(5,5)
10
>>> addTwo(5, 's')
Oh noes 

If those are your actual functions it would be easy to generalize them.

You could create one general function

def general(bottom_num, top_num):
  num=random.random()
  try:
    if num>top_num: print 'OK'
    elif num>bottom_num: raise NameError('Too Small')
    else: raise KeyboardInterrupt
  except NameError:
    print "%s had a NameError" % sys._getframe().f_code.co_name
  except:
    print "%s had a different Error" % sys._getframe().f_code.co_name

this would keep your code from repeating and address the try: except: issue

I ran into the same scenario recently, in my case I have some custom exceptions based on which I need to log or raise the Exception further. I have created a decorator method to handle the exceptions as per type.

try:
   obj.some_method()
except Exception as e:
    catch_and_log_exception(e)


def catch_and_log_exception(e):
    if isinstance(e, MyConnectionError):
        print "Connection error : %s." % e.message
        sys.exit(1)
    elif isinstance(e, MyConnectionTimeout):
        print "Connection to server has been timed out. %s" % e.message
        sys.exit(1)
    elif isinstance(e, MyException):
        message = e.explanation if e.explanation else e.message
        log_error_message(str(message))
        print "Failed, please check the logs."
        sys.exit(1)
    else:
        raise e

Hope this help !!

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top