Introducción al concepto de decorador

PythonPythonBeginner
Practicar Ahora

This tutorial is from open-source community. Access the source code

💡 Este tutorial está traducido por IA desde la versión en inglés. Para ver la versión original, puedes hacer clic aquí

Introducción

Esta sección introduce el concepto de un decorador. Este es un tema avanzado del que solo rozamos la superficie.

Ejemplo de registro

Consideremos una función.

def add(x, y):
    return x + y

Ahora, consideremos la función con un poco de registro agregado.

def add(x, y):
    print('Calling add')
    return x + y

Ahora una segunda función también con un poco de registro.

def sub(x, y):
    print('Calling sub')
    return x - y

Observación

Observación: Es algo repetitivo.

Escribir programas donde hay mucha replicación de código suele ser realmente molesto. Son tediosos de escribir y difíciles de mantener. Especialmente si decides que quieres cambiar cómo funciona (por ejemplo, quizás un tipo diferente de registro).

Código que agrega registro

Quizás puedas crear una función que agregue registro a otras funciones. Un envoltorio.

def logged(func):
    def wrapper(*args, **kwargs):
        print('Calling', func.__name__)
        return func(*args, **kwargs)
    return wrapper

Ahora úsalo.

def add(x, y):
    return x + y

logged_add = logged(add)

¿Qué pasa cuando llamas a la función devuelta por logged?

logged_add(3, 4)      ## Verás que aparece el mensaje de registro

Este ejemplo ilustra el proceso de creación de una llamada función envoltorio.

Un envoltorio es una función que se encierra alrededor de otra función con un poco de procesamiento adicional, pero de otra manera funciona exactamente de la misma manera que la función original.

>>> logged_add(3, 4)
Llamando a add   ## Salida adicional. Agregada por el envoltorio
7
>>>

Nota: La función logged() crea el envoltorio y lo devuelve como resultado.

Decoradores

Poner envoltorios alrededor de funciones es extremadamente común en Python. Tan común que hay una sintaxis especial para ello.

def add(x, y):
    return x + y
add = logged(add)

## Sintaxis especial
@logged
def add(x, y):
    return x + y

La sintaxis especial realiza exactamente los mismos pasos que se muestran arriba. Un decorador es solo una nueva sintaxis. Se dice que decora la función.

Comentario

Hay muchos más detalles sutiles sobre los decoradores que los presentados aquí. Por ejemplo, usarlos en clases. O usar múltiples decoradores con una función. Sin embargo, el ejemplo anterior es una buena ilustración de cómo su uso tiende a surgir. Por lo general, es en respuesta al código repetitivo que aparece en una amplia variedad de definiciones de funciones. Un decorador puede mover ese código a una definición central.

Ejercicio 7.10: Un decorador para medir el tiempo

Si defines una función, su nombre y módulo se almacenan en los atributos __name__ y __module__. Por ejemplo:

>>> def add(x,y):
        return x+y

>>> add.__name__
'add'
>>> add.__module__
'__main__'
>>>

En un archivo timethis.py, escribe una función decoradora timethis(func) que envuelva una función con una capa adicional de lógica que imprime cuánto tiempo tarda en ejecutarse una función. Para hacer esto, rodearás la función con llamadas de medición del tiempo como esta:

start = time.time()
r = func(*args,**kwargs)
end = time.time()
print('%s.%s: %f' % (func.__module__, func.__name__, end-start))

Aquí hay un ejemplo de cómo debería funcionar tu decorador:

>>> from timethis import timethis
>>> @timethis
def countdown(n):
    while n > 0:
        n -= 1

>>> countdown(10000000)
__main__.countdown : 0.076562
>>>

Discusión: Este decorador @timethis se puede colocar delante de cualquier definición de función. Por lo tanto, es posible que lo uses como una herramienta de diagnóstico para el ajuste de rendimiento.

✨ Revisar Solución y Practicar

Resumen

¡Felicidades! Has completado el laboratorio de Decoradores de Funciones. Puedes practicar más laboratorios en LabEx para mejorar tus habilidades.