Decoradores de clase para métodos en clases
¿Cómo funcionan los decoradores de clase para métodos en clases? Aquí hay un ejemplo de lo que he hecho a través de experimentos:
from functools import wraps
class PrintLog(object):
def __call__(self, func):
@wraps(func)
def wrapped(*args):
print('Soy un registro')
return func(*args)
return wrapped
class foo(object):
def __init__(self, rs: str) -> None:
self.ter = rs
@PrintLog()
def baz(self) -> None:
print('dentro de baz')
bar = foo('2')
print('ejecutando bar.baz()')
bar.baz()
Y esto funciona perfectamente bien. Sin embargo, tenía la impresión de que los decoradores no necesitan ser llamados con ()
, pero cuando quito los corchetes de @PrintLog()
, obtengo este error:
def baz(self) -> None:
TypeError: PrintLog() no recibe argumentos
¿Hay algo que me esté faltando / no entiendo? También he intentado pasar un argumento de desecho con __init__()
, y funciona.
class PrintLog(object):
def __init__(self, inútil):
print(inútil)
def __call__(self, func):
@wraps(func)
def wrapped(*args):
print('Soy un registro')
return func(*args)
return wrapped
class foo(object):
def __init__(self, rs: str) -> None:
self.ter = rs
@PrintLog("argumento inútil que estoy pasando a __init__")
def baz(self) -> None:
print('dentro de baz')
De nuevo, esto funciona, pero no quiero pasar ningún argumento al decorador.
En resumen: Esta pregunta en Python 3.x.
¡Ayuda apreciada!
davy.ai
Los decoradores de clase para métodos en clases funcionan modificando o mejorando el comportamiento del método que están decorando. En el código de ejemplo proporcionado, el decorador de clase
PrintLog
se utiliza para imprimir un mensaje de registro antes de que se ejecute el métodobaz
.La razón por la que el decorador necesita ser llamado con
()
es porque está definido como un objeto llamable (método__call__
) que devuelve otro objeto llamable (funciónwrapped
) que será en realidad llamado cuando se invoque el método.Cuando se trata de eliminar
()
de@PrintLog
, Python lo interpreta como un intento de llamar a la propia clasePrintLog
(no a una instancia de la clase) sin argumentos, lo que produce unTypeError
.Para evitar pasar cualquier argumento al decorador, se puede modificar el método
__init__
de la clasePrintLog
para aceptar argumentos opcionales con valores por defecto. Por ejemplo:Ahora se puede usar
@PrintLog()
sin pasar ningún argumento, y utilizará el mensaje predeterminado definido en el constructor dePrintLog
. O se puede pasar un mensaje diferente si se quiere personalizar:@PrintLog("Mensaje personalizado")
.