Repetitive Try and Except Clauses

心不动则不痛 提交于 2019-12-18 04:41:54

问题


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?


回答1:


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.




回答2:


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)



回答3:


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 



回答4:


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




回答5:


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 !!



来源:https://stackoverflow.com/questions/9386592/repetitive-try-and-except-clauses

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!