8

Ich möchte verschiedene Funktionen nur ausführen, wenn der angemeldete Benutzer die erforderliche Berechtigungsstufe hat.Dekorator zum Festlegen von Attributen der Funktion

Um mein Leben komplexer zu machen, möchte ich einfach Dekorateure verwenden. Im Folgenden habe ich versucht, das Attribut permission auf "dekorierte" Funktionen zu setzen - wie unten gezeigt.

def permission(permission_required): 
    def wrapper(func): 
     def inner(*args, **kwargs): 
      setattr(func, 'permission_required', permission_required) 
      return func(*args, **kwargs) 
     return inner 
    return wrapper 

@permission('user') 
def do_x(arg1, arg2): 

    ... 

@permission('admin') 
def do_y(arg1, arg2): 
    ... 

Aber wenn ich tue:

fn = do_x 
if logged_in_user.access_level == fn.permission_required: 
    ... 

Ich erhalte einen Fehler 'function' object has no attribute 'permission_required'

Was bin ich?

+1

Als Randbemerkung: ich bin ziemlich sicher, dass Sie [ 'functools.wraps'] verwenden möchten (http://docs.python.org/2/library/functools.html#functools.wraps) Hier. Nicht um dein Problem direkt zu lösen, aber weil es so gut wie unmöglich ist, diese Art von Code zu debuggen, wenn jede Funktion mit dem Namen 'inner 'endet, wobei' (^ args, ** kwargs) ',' inspect' an die falsche Quelle geht, usw. – abarnert

Antwort

14

Sie setzen das Attribut in der inneren (Wrapper) -Funktion. Sie brauchen nicht eine Wrapper-Funktion bei allen:

def permission(permission_required): 
    def decorator(func): 
     func.permission_required = permission_required 
     return func 
    return decorator 

Ihr Dekorateur muss etwas zurück, dass die ursprüngliche Funktion ersetzen werden. Die ursprüngliche Funktion selbst (mit dem hinzugefügten Attribut) ist dafür geeignet, da Sie nur ein Attribut hinzufügen möchten.

Wenn Sie noch einen Wrapper benötigen, dann setzen Sie das Attribut auf die Wrapper-Funktion statt:

def permission(permission_required): 
    def decorator(func): 
     def wrapper(*args, **kwargs): 
      # only use a wrapper if you need extra code to be run here 
      return func(*args, **kwargs) 
     wrapper.permission_required = permission_required 
     return wrapper 
    return decorator 

Immerhin ersetzen Sie die verpackte Funktion mit dem Wrapper von dem Dekorateur zurückgegeben, so dass das sind Objekt suchen Sie nach dem Attribut auf.

+0

Ich brauche den Wrapper, um Argumente in der verzierten Funktion zuzulassen. Ich habe Ihren Code verwendet und es hat gut funktioniert - aber wenn ich Wrapper für Argumente hinzugefügt habe, kam der Fehler zurück. – rikAtee

+1

@rikAtee: Sie benötigen keinen Wrapper, um Argumente in der dekorierten Funktion zuzulassen. Im ersten Beispiel wird nur die Funktion geändert und zurückgegeben. es braucht immer noch dieselben Argumente wie vor der Dekoration. – abarnert

+0

@rikAtee: In der Tat ist der Wrapper * nicht * erforderlich, wenn Sie nur das Attribut setzen. Fügen Sie nur einen Wrapper hinzu, wenn ein Wrapper benötigt wird (z. B. wird zusätzlicher Code hinzugefügt, um mit den Argumenten oder den Rückgabewerten zu arbeiten, oder es werden zusätzliche Dinge ausgeführt, wenn die Funktion aufgerufen wird). –

1

Ihr Dekorateur sollte eine Funktion zurück, die do_x oder do_y ersetzen kann, nicht das Ausführungsergebnis von do_x zurückgeben oder do_y Sie können Sie wie unten modity dekorieren:

def permission(permission_required): 
    def wrapper(func): 
     def inner(): 
      setattr(func, 'permission_required', permission_required) 
      return func 
     return inner() 
    return wrapper 

Natürlich haben Sie eine weitere kurze Lösung :

def permission(permission_required): 
    def wrapper(func): 
     setattr(func, 'permission_required', permission_required) 
     return func 
    return wrapper 
+1

Ihre innere Funktion macht * nichts *, also ersetzen Sie das Original durch eine Funktion, die nichts anderes tut, als ein Attribut auf die umbrochene Funktion zu setzen, was es * nutzlos macht. –

Verwandte Themen