2013-02-05 52 views
25

我想用一個裝飾器來處理各種函數的審計(主要是Django視圖函數,但不是唯一的)。爲了做到這一點,我希望能夠審計功能執行後 - 即該函數正常運行,如果它沒有例外返回,則裝飾器記錄事實。如何在裝飾函數完成後讓Python裝飾器運行?

喜歡的東西:

@audit_action(action='did something') 
def do_something(*args, **kwargs): 
    if args[0] == 'foo': 
     return 'bar' 
    else: 
     return 'baz' 

當函數完成後audit_action將只運行。

回答

26

修飾器通常返回一個包裝函數;只需在調用包裝函數後將你的邏輯放入包裝函數中即可。

def audit_action(action): 
    def decorator_func(func): 
     def wrapper_func(*args, **kwargs): 
      # Invoke the wrapped function first 
      retval = func(*args, **kwargs) 
      # Now do something here with retval and/or action 
      print 'In wrapper_func, handling action {!r} after wrapped function returned {!r}'.format(action, retval) 
      return retval 
     return wrapper_func 
    return decorator_func 

所以audit_action(action='did something')是一個裝飾工廠,返回一個作用域decorator_func,這是用來裝飾你的do_somethingdo_something = decorator_func(do_something))。

裝修後,您的do_something參考文獻已被wrapper_func替代。調用wrapper_func()會導致原來的do_something()被調用,然後你的代碼在包裝器func可以做的事情。

上面的代碼,再加上你的榜樣作用,給出了以下的輸出:

>>> do_something('foo') 
In wrapper_func, handling action 'did something' after wrapped function returned 'bar' 
'bar' 
+2

你不知道有多少個不同的組合裝飾,包裝,功能和retvals我用盡了這個工作。不僅感謝代碼,而且感謝您的解釋。 –

3

你的裝飾可以在這裏自己來處理它,就像

def audit_action(function_to_decorate): 
    def wrapper(*args, **kw): 
     # Calling your function 
     output = function_to_decorate(*args, **kw) 
     # Below this line you can do post processing 
     print "In Post Processing...." 
    return wrapper 
+0

OP發佈的示例使用了一個用'action'參數調用的裝飾器工廠。你需要另一層範圍或類別.. –

+0

根據OP的例子更新了答案:) – avasal