2010-11-22 52 views
14

我有一個可能會引發異常的python函數。調用者捕獲異常並處理它。現在我想添加一個裝飾器到那個函數,捕獲異常,做一些處理,但然後重新引發異常,以允許原始調用者來處理它。這是有效的,除了當原始調用者從異常中顯示調用堆棧時,它顯示了修飾器中重新生成的行,而不是它最初發生的位置。示例代碼:如何在裝飾器中捕獲異常但允許調用者抓住它?

import sys,traceback 

def mydec(func): 
    def dec(): 
     try: 
      func() 
     except Exception,e: 
      print 'Decorator handled exception %s' % e 
      raise e 
    return dec 

@mydec 
def myfunc(): 
    x = 1/0 

try: 
    myfunc() 
except Exception,e: 
    print 'Exception: %s' % e 
    type,value,tb = sys.exc_info() 
    traceback.print_tb(tb) 

輸出是:

Decorator handled exception integer division or modulo by zero 
Exception: integer division or modulo by zero 
    File "allbug.py", line 20, in <module> 
    myfunc() 
    File "allbug.py", line 9, in dec 
    raise e 

我想裝飾到能夠處理的異常,但回溯應註明x = 1/0線,而不是raise線。我怎樣才能做到這一點?

回答

17

只需在catch塊中使用raise;(即不要提高任何特定值,只需raise;),以重新引發異常而不「重置」回溯。

+0

只要是明確的,只要用一個赤裸裸的「提高」的語句。不要指定要提出的內容。 – drxzcl 2010-11-22 20:34:10

8

我剛剛寫了一個類似於你正在做的類,但有更多的選項可用。那就是:

class ErrorIgnore(object): 
    def __init__(self, errors, errorreturn = None, errorcall = None): 
     self.errors = errors 
     self.errorreturn = errorreturn 
     self.errorcall = errorcall 

    def __call__(self, function): 
     def returnfunction(*args, **kwargs): 
     try: 
      return function(*args, **kwargs) 
     except Exception as E: 
      if type(E) not in self.errors: 
       raise E 
      if self.errorcall is not None: 
       self.errorcall(E, *args, **kwargs) 
      return self.errorreturn 
     return returnfunction 

常見的用法是這樣的:

def errorcall(E, *args): 
    print 'exception skipped', E 

@ErrorIgnore(errors = [ZeroDivisionError, ValueError], errorreturn = None, errorcall = errorcall) 
def myfunction(stuff): 
    # do stuff 
    # return stuff 
    # the errors shown are skipped