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.

El Decorador solo funciona cuando un método está decorado, pero no cuando el decorador se llama con el método pasado como argumento.

Escucha desde hace mucho tiempo; primera vez que llama, así que por favor no me critiques si no he seguido perfectamente las pautas.

Estoy intentando crear un decorador que aplique una barra de progreso a un método generador. Mi decorador funciona perfectamente cuando se usa la sintaxis @decorator. Sin embargo, cuando llamo al decorador y paso un método como argumento, el decorador no hace nada en absoluto. Me gustaría llamar a la función decoradora como cualquier otra función en lugar de usar @status_bar porque quiero una forma simple de usar opcionalmente el generador.

Aquí está el código funcionando:

import time

from alive_progress import alive_bar

def status_bar(func):

def wrapper(self):
    with alive_bar() as bar:
        for x in func(self):
            bar()

return wrapper

class TestClass:

def __init__(self):
    pass

@status_bar
def iter_range(self):
    for x in range(10000):
        time.sleep(0.01)
        yield x

TestClass().iter_range()

Esto devuelve una barra de progreso en la consola como se esperaba.

| ▶▶▶▶▶▶▶▶▶▶▶▶▶ | ▂▂▄ 326 en 3s (98.2/s)

Pero al ejecutar el código sin el azúcar sintáctico, no hace nada.

def status_bar(func):

def wrapper(self):
    with alive_bar() as bar:
        for x in func(self):
            bar()

return wrapper

class TestClass:

def __init__(self):
    pass

def iter_range(self):
    for x in range(10000):
        time.sleep(0.01)
        yield x

status_bar(TestClass().iter_range)

En cambio, el código se ejecuta como si no se hubiera llamado a ninguna función.

Proceso finalizado con el código de salida 0

Siempre obtengo la misma salida y sé que hay una explicación sencilla aquí, por eso me molesta tanto no poder hacer que funcione. Cualquier ayuda es muy apreciada. Gracias.

Tags:  , ,

Answer

  1. Avatar for davy.ai

    La razón por la que el segundo fragmento de código no funciona es que status_bar(TestClass().iter_range) solo devuelve la función envoltorio, no la ejecuta. Para que funcione, debes ejecutar la función envoltorio devuelta por el decorador. Puedes hacerlo asignando la función decorada a una variable y luego llamando a esa variable:

    decorated_func = status_bar(TestClass().iter_range)
    decorated_func()
    

    Alternativamente, puedes modificar el decorador para que devuelva directamente la función decorada:

    def status_bar(func):
        def wrapper(self):
            with alive_bar() as bar:
                for x in func(self):
                    bar()
        return wrapper(self)  # ejecuta la función envuelta y devuelve el resultado
    

    Con este cambio, puedes llamar a la función decorada de la siguiente manera:

    TestClass().iter_range = status_bar(TestClass().iter_range)  # decorar la función
    TestClass().iter_range()  # ejecutar la función decorada
    

Comments are closed.