es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

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!

Tags:  , , , ,

Answer

  1. Avatar for 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étodo baz.

    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ón wrapped) 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 clase PrintLog (no a una instancia de la clase) sin argumentos, lo que produce un TypeError.

    Para evitar pasar cualquier argumento al decorador, se puede modificar el método __init__ de la clase PrintLog para aceptar argumentos opcionales con valores por defecto. Por ejemplo:

    class PrintLog(object):
    
        def __init__(self, message="Soy un registro"):
            self.message = message
    
        def __call__(self, func):
            @wraps(func)
            def wrapped(*args):
                print(self.message)
                return func(*args)
            return wrapped
    

    Ahora se puede usar @PrintLog() sin pasar ningún argumento, y utilizará el mensaje predeterminado definido en el constructor de PrintLog. O se puede pasar un mensaje diferente si se quiere personalizar: @PrintLog("Mensaje personalizado").

Comments are closed.