2017-03-06 3 views
0

So ist ein nicht-funktionierendes Beispiel das, was zeigt Ich versuche, bei bekommenPython Dekorateure mit Instanz-Level-Informationen

class TestClass(object): 

    def require_debug_mode(self, f): 
     def func_wrapper(*args, **kwargs): 
      if self.debug_mode: 
       return f(*args, **kwargs) 
     return func_wrapper 

    def __init__(self, debug_mode): 
     self.debug_mode = debug_mode 

    @require_debug_mode 
    def print_message(self, msg): 
     print msg 

Sie können die gewünschten print_message wie folgt neu schreiben:

def print_message(self, msg): 
    if self.debug_mode: 
     print msg 

Ich möchte im Wesentlichen in der Lage sein, Methoden zu dekorieren, die bestimmte Überprüfungen durchführen (ohne diese Überprüfung in jeder Methode zu wiederholen, die sie verwenden könnte). Diese Prüfungen benötigen jedoch Zugriff auf Informationen auf Instanzebene. Ist das überhaupt möglich?

+0

Ja, es ohne weiteres möglich ist. Sie haben gerade den Parameter 'self' an die falsche Stelle gesetzt. Es ist die Funktion _inner_, die den Parameter self benötigt. –

Antwort

1

haben, um den Dekorateur als Teil der Klasse, die Sie diesen Code verwenden können:

class TestClass(object): 

    def require_debug_mode(f): 
     def func_wrapper(self, *args, **kwargs): 
      if self.debug_mode: 
       return f(self, *args) 
     return func_wrapper 

    def __init__(self, debug_mode): 
     self.debug_mode = debug_mode 

    @require_debug_mode 
    def print_message(self, msg): 
     print(msg) 

tc_obj = TestClass(True) 
tc_obj.print_message("debug msg") 
# debug msg 

tc_obj = TestClass(False) 
tc_obj.print_message("debug msg") 
# no output 

Um den Dekorateur außerhalb der Klasse halten Sie die

folgenden Ansatz verwenden können
def require_debug_mode(f): 
    def wrapper(*args): 
     if args[0].debug_mode: 
      return f(*args) 
    return wrapper 

class TestClass(object): 
    def __init__(self, debug_mode): 
     self.debug_mode = debug_mode 

    @require_debug_mode 
    def print_message(self, msg): 
     print(msg) 

tc_obj = TestClass(True) 
tc_obj.print_message("debug msg") 
# debug msg 

tc_obj = TestClass(False) 
tc_obj.print_message("debug msg") 
# no output 
0

Die Dekorierer erhalten die gleichen Argumente wie die regulären Methoden, was bedeutet, dass self auch für den Dekorator verfügbar ist. Das Problem mit Ihrem Code ist, dass Sie erwarten, dass der äußere Wrapper auch das self Argument bekommt, was nicht der Fall ist (es wird zur Deklarationszeit aufgerufen, es gibt zu diesem Zeitpunkt keine Instanz).

Zum Beispiel:

import functools 


class TestClass(object): 

    def require_debug_mode(function): 

     @functools.wraps(function) 
     def _require_debug_mode(self, *args, **kwargs): 
      assert self.debug_mode, 'Debug mode is required for %r' % function 
      return function(self, *args, **kwargs) 

     return _require_debug_mode 

    def __init__(self, debug_mode): 
     self.debug_mode = debug_mode 

    @require_debug_mode 
    def print_message(self, msg): 
     print msg 


test_class = TestClass(True) 
test_class.print_message('ping') 

test_class = TestClass(False) 
test_class.print_message('pong') 

Output:

ping 
Traceback (most recent call last): 
    ... 
AssertionError: Debug mode is required for <function print_message at 0x...> 
shell returned 1 
0

Dekorateur ist eine Funktion, die eine Funktion als Eingabe gegeben, eine Funktion als Ausgang liefert.

Sie möchten als Funktion print_message(self, msg) eingeben. Das ist gut.

Damit der Decorator effektiv funktioniert, muss die resultierende Funktion ein ähnliches Verhalten haben. Sie will also die Funktion wickeln, Decodierung gerade genug Argumente „späht“ zu aktivieren, um zu sehen, was Sie wollen:

def func_wrapper(self, *args, **kwargs): 
    if self.debug_mode: 
     return self.f(*args, **kwargs) 
Verwandte Themen