Decorator-Klassen in Python
Frage
Ich möchte Klassen für so Dekorateure mit den folgenden Grundsätzen Gebrauch konstruieren intakt:
- Es sollte möglich sein, mehrere solche Klasse Dekorateure auf off 1 Funktion zu stapeln.
- Die resultierenden Funktionsnamen Zeiger sollten ohne Dekorateur aus der gleichen Funktion nicht zu unterscheiden sein, außer vielleicht für nur welche Art / Klasse ist.
- die Dekorateure Bestellung aus nicht relevant sein sollte, es sei denn, tatsächlich von den Dekorateuren beauftragt. D. h. unabhängige Dekorateure in beliebiger Reihenfolge angewandt werden könnten.
Dies ist für ein Django-Projekt, und der spezielle Fall arbeite ich jetzt auf das Verfahren benötigt 2 Dekorateure, und als eine normale Python-Funktion angezeigt werden:
@AccessCheck
@AutoTemplate
def view(request, item_id) {}
@AutoTemplate ändert sich die Funktion, so dass stattdessen eine Httpresponse zurückzukehren, es ist nur ein Wörterbuch zur Verwendung kehrt in den Kontext. Ein Request verwendet wird, und der Vorlagenname wird aus dem Methodennamen und Modul zu entnehmen.
@AccessCheck fügt zusätzliche Kontrollen der Benutzer auf der Grundlage der item_id.
Ich vermute, es ist nur der Konstruktor richtig zu machen und die entsprechenden Attribute kopieren, aber welche Attribute sind diese?
Das folgende Dekorateur wird nicht funktionieren, wie ich beschreiben:
class NullDecl (object):
def __init__ (self, func):
self.func = func
def __call__ (self, * args):
return self.func (*args)
Wie der folgende Code demonstriert:
@NullDecl
@NullDecl
def decorated():
pass
def pure():
pass
# results in set(['func_closure', 'func_dict', '__get__', 'func_name',
# 'func_defaults', '__name__', 'func_code', 'func_doc', 'func_globals'])
print set(dir(pure)) - set(dir(decorated));
Darüber hinaus versuchen, und fügen Sie im NullDecl Konstruktor, und es wird zum ersten Dekorateur arbeiten, aber nicht die zweite "print Func Namen .." - als Name fehlt wird
Refined eduffy 's ein wenig beantworten, und es scheint ziemlich gut zu funktionieren:
class NullDecl (object):
def __init__ (self, func):
self.func = func
for n in set(dir(func)) - set(dir(self)):
setattr(self, n, getattr(func, n))
def __call__ (self, * args):
return self.func (*args)
def __repr__(self):
return self.func
Lösung
Eine do-nothing Dekorateur Klasse würde wie folgt aussehen:
class NullDecl (object):
def __init__ (self, func):
self.func = func
for name in set(dir(func)) - set(dir(self)):
setattr(self, name, getattr(func, name))
def __call__ (self, *args):
return self.func (*args)
Und dann kann man es gilt in der Regel:
@NullDecl
def myFunc (x,y,z):
return (x+y)/z
Andere Tipps
Die Dekorateur Modul hilft Ihnen das Schreiben Signatur erhalt Dekorateure.
Und die PythonDecoratorLibrary könnten nützliche Beispiele für Dekorateure bieten.
einen Dekorateur zu erstellen, die Funktionen in einer Angelegenheit Wraps, die sie nicht mehr von der ursprünglichen Funktion zu machen, verwenden Sie functools.wraps
.
Beispiel:
def mydecorator(func):
@functools.wraps(func):
def _mydecorator(*args, **kwargs):
do_something()
try:
return func(*args, **kwargs)
finally:
clean_up()
return _mydecorator
# ... and with parameters
def mydecorator(param1, param2):
def _mydecorator(func):
@functools.wraps(func)
def __mydecorator(*args, **kwargs):
do_something(param1, param2)
try:
return func(*args, **kwargs)
finally:
clean_up()
return __mydecorator
return _mydecorator
(meine persönliche Präferenz ist Dekorateure mit Funktionen zu erstellen, nicht Klassen)
Die Bestellung von Dekorateure ist wie folgt:
@d1
@d2
def func():
pass
# is equivalent to
def func():
pass
func = d1(d2(func))