2013-02-05 9 views
25

Ich möchte einen Dekorator verwenden, um das Auditing verschiedener Funktionen (hauptsächlich Django-View-Funktionen, aber nicht ausschließlich) zu überwachen. Um dies zu tun, möchte ich in der Lage sein, die Funktion nach der Ausführung zu auditieren - d. H. Die Funktion läuft wie normal, und wenn sie ohne eine Ausnahme zurückkehrt, dann protokolliert der Dekorator die Tatsache.Wie kann ich einen Python-Dekorator ausführen, nachdem die dekorierte Funktion abgeschlossen wurde?

Etwas wie:

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

Wo audit_action würde nur ausgeführt, nachdem die Funktion beendet ist.

Antwort

26

Dekoratoren geben normalerweise eine Wrapper-Funktion zurück; Fügen Sie Ihre Logik einfach in die Wrapper-Funktion ein, nachdem Sie die Wrapped-Funktion aufgerufen haben.

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 

So audit_action(action='did something') ist ein Dekorateur Fabrik, die eine scoped decorator_func zurückgibt, die verwendet wird, Ihre do_something (do_something = decorator_func(do_something)) zu dekorieren.

Nach dem Dekorieren wurde Ihre do_something Referenz durch wrapper_func ersetzt. Aufruf wrapper_func() verursacht die ursprüngliche do_something() aufgerufen werden, und dann Ihren Code in der Wrapper-Funktion kann Dinge tun.

Der obige Code, kombiniert mit Beispielfunktion, gibt die folgende Ausgabe:

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

Sie keine Ahnung, wie viele verschiedene Kombinationen von Decorator, Wrapper, Func und Retvals habe ich aufgebraucht, um das zum Laufen zu bringen. Danke nicht nur für den Code, sondern für die Erklärung. –

3

Ihr Dekorateur es hier selbst behandeln kann, wie

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

Das Beispiel, das das OP gepostet hat, verwendete eine Decorator Factory, die mit einem 'action' Argument aufgerufen wurde. Sie brauchen eine andere Ebene des Scoping oder eine Klasse .. –

+0

aktualisiert die Antwort nach OP Beispiel :) – avasal

Verwandte Themen