las clases de decorador en Python
Pregunta
Quiero que construya clases para su uso como decoradores con los siguientes principios intactos:
- Debe ser posible apilar múltiples tales decoradores de clase en la parte superior de 1 función.
- El puntero del nombre de la función resultante debe ser indistinguible de la misma función sin un decorador, excepto tal vez por sólo el tipo / clase que es.
- ordenar del decoradores no deben ser pertinentes a menos que en realidad el mandato de los decoradores. Es decir. decoradores independientes se podrían aplicar en cualquier orden.
Esto es para un proyecto de Django, y el caso específico que estoy trabajando ahora el método necesita 2 decoradores, y que aparezca como una función normal de Python:
@AccessCheck
@AutoTemplate
def view(request, item_id) {}
@AutoTemplate cambia la función para que en lugar de devolver un HttpResponse, simplemente devuelve un diccionario para su uso en el contexto. Se utiliza un RequestContext, y el nombre de la plantilla se infiere a partir del nombre del método y el módulo.
@AccessCheck agrega controles adicionales en el usuario basado en el item_id.
Estoy adivinando que es sólo para obtener el derecho constructor y copiar los atributos adecuados, pero que atribuye es esto?
La siguiente decorador no funcionará como se describo:
class NullDecl (object):
def __init__ (self, func):
self.func = func
def __call__ (self, * args):
return self.func (*args)
Como se ha demostrado por el siguiente código:
@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));
Además, tratar de añadir en el constructor NullDecl, y que funcionará para el primer decorador, pero no el segundo "Func impresión nombre ." -. Como el nombre no podrá contar
Refinado eduffy 's responder un poco, y parece que funciona bastante bien:
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
Solución
Una clase decoradora que no hace nada se vería así:
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)
Y a continuación, se puede aplicar normalmente:
@NullDecl
def myFunc (x,y,z):
return (x+y)/z
Otros consejos
El decorador módulo le ayuda a escribir decoradores firma-preservación.
Y el PythonDecoratorLibrary podría proporcionar ejemplos útiles para decoradores.
Para crear un decorador que envuelve las funciones en cuestión que los hacen indistinguibles de la función original, use functools.wraps
.
Ejemplo:
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
(mi preferencia personal es crear decoradores mediante funciones, no clases)
El orden de decoradores es como sigue:
@d1
@d2
def func():
pass
# is equivalent to
def func():
pass
func = d1(d2(func))