2013-02-05 14 views
25

Chcę użyć dekoratora do obsługi audytu różnych funkcji (głównie funkcji widoku Django, ale nie wyłącznie). W tym celu chciałbym mieć możliwość audytu funkcji po wykonaniu - tj. Funkcja działa jak normalnie, a jeśli zwraca się bez wyjątku, wówczas dekorator rejestruje fakt.Jak mogę uruchomić dekorator Python po zakończeniu funkcji dekorowania?

Coś jak:

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

Gdzie audit_action będzie działać dopiero po funkcja została zakończona.

Odpowiedz

26

Dekoratorzy zazwyczaj zwracają funkcję owijania; po prostu umieść swoją logikę w funkcji opakowania po wywołaniu funkcji opakowanej.

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 

Więc audit_action(action='did something') jest fabryka dekorator, która zwraca scoped decorator_func, który jest używany do dekoracji do_something (do_something = decorator_func(do_something)).

Po zakończeniu dekoracji numer do_something został zastąpiony numerem wrapper_func. Wywołanie wrapper_func() powoduje wywołanie oryginalnego do_something(), a następnie kod w opakowaniu func może robić różne rzeczy.

Powyższy kod, w połączeniu z np funkcji, daje następujący wynik:

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

nie masz pojęcia, jak wiele różnych kombinacjach dekorator, wrapper, func i retry, których użyłem próbując zmusić to do działania. Dziękuję nie tylko za kod, ale za wyjaśnienie. –

3

Twój dekorator może go obsłużyć tutaj sama, jak

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

W przykładzie, który opublikował OP, używana była fabryka dekoratorów z argumentem "akcja". Potrzebujesz kolejnej warstwy zakresu lub klasy .. –

+0

zaktualizował odpowiedź zgodnie z przykładem OP :) – avasal

Powiązane problemy