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.

Obtener el nombre de la función cuando se utiliza ContextDecorator como decorador.

Tengo el siguiente gestor de contexto y decorador para medir el tiempo de cualquier función o bloque de código:

import time
from contextlib import ContextDecorator

class timer(ContextDecorator):
    def <strong>init</strong>(self, label: str):
        self.label = label

<pre><code>def __enter__(self):
    self.start_time = time.perf_counter()
    return self

def __exit__(self, *exc):
    net_time = time.perf_counter() - self.start_time
    print(f"{self.label} tomó {net_time:.1f} segundos")
    return False
</code></pre>

Se puede usar como gestor de contexto:

with timer("mi bloque de código"):
    time.sleep(2)

<h1>mi bloque de código tomó 2.0 segundos</h1>

También se puede usar como decorador:

@timer("mi<em>func")
def mi</em>func():
    time.sleep(3)

mi_func()

<h1>mi_func tomó 3.0 segundos</h1>

Lo único que no me gusta es tener que pasar manualmente el nombre de la función como la etiqueta cuando se usa como decorador. Me encantaría que el decorador use automáticamente el nombre de la función si no se pasa una etiqueta:

@timer()
def mi_func():
    time.sleep(3)

mi_func()

<h1>mi_func tomó 3.0 segundos</h1>

¿Hay alguna manera de hacer esto?

Tags:  , ,

Answer

  1. Avatar for davy.ai

    Sí, es posible modificar el decorador timer para utilizar automáticamente el nombre de la función como etiqueta si no se pasa ninguna etiqueta. Esto se puede hacer modificando el método __init__ de la clase timer para comprobar si se pasa una etiqueta, y si no, utilizar el nombre de la función decorada en su lugar:

    import time
    from contextlib import ContextDecorator
    
    
    class timer(ContextDecorator):
        def __init__(self, label=None):
            if label is None:
                label = self.__class__.__name__
            self.label = label
    
        def __enter__(self):
            self.start_time = time.perf_counter()
            return self
    
        def __exit__(self, *exc):
            net_time = time.perf_counter() - self.start_time
            print(f"{self.label} tardó {net_time:.1f} segundos")
            return False
    

    En esta versión modificada de la clase timer, el método __init__ ahora recibe un argumento label opcional, que por defecto es None. Si no se pasa etiqueta, se utiliza el atributo __class__.__name__ para obtener el nombre de la función decorada. Este es el nombre de la clase a la que se ha adjuntado el decorador, que en este caso debería ser la función decorada.

    Con esta modificación, ahora es posible utilizar el decorador timer sin pasar una etiqueta, y se utilizará automáticamente el nombre de la función decorada:

    @timer()
    def mi_funcion():
        time.sleep(3)
    
    mi_funcion()
    # mi_funcion tardó 3.0 segundos
    

Comments are closed.