Domanda
Voglio costruire le classi per l'uso come decoratori con i seguenti principi intatta:
- Dovrebbe essere possibile impilare più tali decoratori di classe 1 sulla parte superiore fuori funzione.
- Il puntatore nome della funzione risultante dovrebbe essere indistinguibile dalla stessa funzione, senza un decoratore, salvo forse solo per il tipo / classe è.
- ordinare dal decoratori non dovrebbero essere rilevanti se non in realtà mandato dai decoratori. Vale a dire. decoratori indipendenti potrebbero essere applicati in qualsiasi ordine.
Questo è per un progetto Django, e il caso specifico sto lavorando ora il metodo ha bisogno 2 decoratori, e di apparire come una funzione Python normale:
@AccessCheck
@AutoTemplate
def view(request, item_id) {}
@AutoTemplate cambia la funzione in modo che invece di restituire un HttpResponse, semplicemente restituisce un dizionario per l'utilizzo nel contesto. Un RequestContext viene utilizzato, e il nome del modello è dedotto dal nome del metodo e il modulo.
@AccessCheck aggiunge ulteriori controlli per l'utente in base alla item_id.
Sono indovinando è solo per ottenere il giusto costruttore e copiare gli attributi appropriati, ma che gli attributi sono?
Il seguente decoratore non funziona come ho descritto:
class NullDecl (object):
def __init__ (self, func):
self.func = func
def __call__ (self, * args):
return self.func (*args)
Come dimostra il seguente codice:
@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));
Inoltre, cercare e aggiungere nel costruttore NullDecl, e si lavorerà per la prima decoratore, ma non il secondo "Funz Stampa nome ." -. Il nome mancheranno
Raffinato eduffy s 'rispondere un po', e sembra funzionare abbastanza bene:
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
Soluzione
Una classe decoratore do-nothing sarebbe simile a questa:
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)
E allora si può applicare normalmente:
@NullDecl
def myFunc (x,y,z):
return (x+y)/z
Altri suggerimenti
Il decoratore modulo vi aiuta a scrivere decoratori firma-conservazione.
E il PythonDecoratorLibrary potrebbe fornire utili esempi per decoratori.
Per creare un decoratore che avvolge le funzioni in una questione che li rendono indistinguibile dalla funzione originale, utilizzare functools.wraps
.
Esempio:
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
(la mia preferenza personale è quello di creare decoratori utilizzando le funzioni, non classi)
L'ordinamento dei decoratori è la seguente:
@d1
@d2
def func():
pass
# is equivalent to
def func():
pass
func = d1(d2(func))