programacion - Cómo decorar los métodos de clase de Python: ¿cómo le paso la instancia al decorador?
poo python 3 (4)
La respuesta de Alex es suficiente cuando una función es suficiente. Sin embargo, cuando necesite una clase, puede hacer que funcione agregando el siguiente método a la clase decoradora.
def __get__(self, obj, objtype):
"""Support instance methods."""
import functools
return functools.partial(self.__call__, obj)
Para entender esto necesitas entender el protocolo descriptor. El protocolo descriptor es el mecanismo para vincular una cosa a una instancia. Consiste en __ obtener __, __ establecer __ y __ eliminar __, que se llaman cuando el objeto se obtiene, configura o elimina del diccionario de instancias.
En este caso, cuando la cosa se obtiene de la instancia, estamos vinculando el primer argumento de su método __ call __ a la instancia, utilizando parcial. Esto se hace automáticamente para las funciones miembro cuando se construye la clase, pero para una función miembro sintética como esta necesitamos hacerlo explícitamente.
Esto es Python 2.5, y también es GAE , no es que importe.
tengo el siguiente código. Estoy decorando el método foo () en la barra, usando la clase dec_check como decorador.
class dec_check(object):
def __init__(self, f):
self.func = f
def __call__(self):
print ''In dec_check.__init__()''
self.func()
class bar(object):
@dec_check
def foo(self):
print ''In bar.foo()''
b = bar()
b.foo()
Al ejecutar esto esperaba ver:
In dec_check.__init__()
In bar.foo()
Pero estoy obteniendo " TypeError: foo() takes exactly 1 argument (0 given)
" como .foo()
, al ser un método de objeto, toma self como argumento. Supongo que el problema es que la instancia de la bar
no existe realmente cuando ejecuto el código de decoración.
Entonces, ¿cómo paso una instancia de bar
a la clase de decorador?
Los decoradores pueden ser un poco complicados en Python. Aquí hay un ejemplo de uno en el que tengo que trabajar en algún momento. Es posible que puedas inferir de lo que estás tratando de hacer.
Autenticación Django y Ajax - URLs que requieren inicio de sesión
Si quieres escribir el decorador como una clase puedes hacerlo:
from functools import update_wrapper, partial
class MyDecorator(object):
def __init__(self, func):
update_wrapper(self, func)
self.func = func
def __get__(self, obj, objtype):
"""Support instance methods."""
return functools.partial(self.__call__, obj)
def __call__(self, obj, *args, **kwargs):
print(''Logic here'')
return self.func(obj, *args, **kwargs)
my_decorator = MyDecorator
class MyClass(object):
@my_decorator
def my_method(self):
pass
__get__
convertir al decorador en un descriptor , ya sea asegurándose de que su (meta) clase tenga un método __get__
o, mucho más sencillo, utilizando una función decoradora en lugar de una clase decoradora (ya que las funciones ya son descriptores). P.ej:
def dec_check(f):
def deco(self):
print ''In deco''
f(self)
return deco
class bar(object):
@dec_check
def foo(self):
print ''in bar.foo''
b = bar()
b.foo()
esto imprime
In deco
in bar.foo
como se desee.