
Los decoradores en Python son una opción del lenguaje para modificar o extender el comportamiento de las funciones o métodos sin cambiar el código. Con lo que se puede crear código más sencillo y legible. Veamos qué son los decoradores en Python y cómo se puede utilizar.
Fundamentos de los decoradores en Python
En Python, las funciones son objetos de primera clase como los números, cadenas o listas. Por lo que se pueden asignar a variables, pasadas como argumentos a otras funciones y devueltas como valores, al igual que el resto de los objetos. Los decoradores son funciones que reciben otra función como argumento y devuelven está modificada o extendida.
La sintaxis básica de un decorador es la que se muestra a continuación.
def mi_decorador(funcion_original): def wrapper(*args, **kwargs): # Código antes de la llamada a la función original resultado = funcion_original(*args, **kwargs) # Código después de la llamada a la función original return resultado return wrapper
Una función (mi_decorador
) que recibe como parámetro una función (funcion_original
). La salida de esta función es otra función (wrapper
) que puede ejecutar código tanto antes como después de llamar a la función original y devuelve un resultado.

Para aplicar un decorador a una función se usa el símbolo @ seguido del nombre del decorador justo antes de la definición de la función que deseas decorar.
@mi_decorador def funcion_a_decorar(*args, **kwargs): # Código de la función original return resultado
Ahora, cuando se llama a la funcion_a_decorar
en realidad estás llamando a wrapper
, la función interna del decorador. Por lo que se puede incluir operaciones antes y después de llamar a la función original.
Esta sintaxis sería el equivalente a, una vez definida la función funcion_a_decorar
, llamar a mi_decorador
con la función anterior como parámetro y asignar el resultado a la función. Es decir, realizar la siguiente operación.
funcion_a_decorar = mi_decorador(funcion_a_decorar)
Usos comunes de decoradores:
Los decoradores se utilizan comúnmente para realizar tareas comunes que se suele ser necesario repetir en múltiples funciones o métodos como las siguientes:
- Log: Los decoradores pueden registrar información sobre cuándo y cómo se llama a una función.
- Autenticación: Los permisos de un usuario para llamar a un método se pueden verificar mediante el uso de decoradores.
- Memoización: La memoización es una técnica para almacenar en caché los resultados de una función (por ejemplo, lo que se puede hacer con lru_cache) y evitar el recálculo si se llama con los mismos argumentos.
- Validación de entrada: Mediante el uso de decoradores se puede verificar que los argumentos de una función cumplan ciertas condiciones antes de ejecutarla.
Ejemplo de uso de decoradores: log de funciones
Uno de los usos más habituales de los decoradores es para incluir trazas en las funciones sin tener que modificar estas. Por ejemplo, si se tiene una función suma
en la que se realiza la suma de dos valores se puede agregar un decorador para que muestre el resultado siempre que se llame a la función.
# Define el decorador def mostrar_resultado(funcion): def wrapper(*args, **kwargs): resultado = funcion(*args, **kwargs) print(f"El resultado de la operación es: {resultado}") return resultado return wrapper # Aplica el decorador a la función sumar @mostrar_resultado def sumar(a, b): return a + b # Llama a la función sumar decorada resultado = sumar(3, 5)
El resultado de la operación es: 8
En este caso la definición del decorador es relativamente sencilla. Este llama a la función original y una vez obtenido el resultado de esta lo muestra por pantalla, antes de devolver el resultado. Así, cuando se llama a la función decorada lo que se obtiene es un mensaje con el resultado.
Mostrar datos de la llamada a la función
Dado que la función wrapper
recibe como entrada **kwargs
se puede usar la información de esta para mejorar la información mostrada. Por ejemplo, se puede incluir el nombre de la función que se ha llamado y los parámetros. Esto se puede conseguir con el siguiente ejemplo.
# Define el decorador def mostrar_resultado(funcion): def wrapper(*args, **kwargs): resultado = funcion(*args, **kwargs) argumentos = ', '.join([f"{k}={v}" for k, v in kwargs.items()] + [str(arg) for arg in args]) print(f"Llamada a {funcion.__name__}({argumentos})") print(f"El resultado de la operación es: {resultado}") return resultado return wrapper # Aplica el decorador a la función sumar @mostrar_resultado def sumar(a, b): return a + b # Llama a la función sumar decorada resultado = sumar(3, 5)
Llamada a sumar(3, 5) El resultado de la operación es: 8
Ejemplo de uso de decoradores: tiempo de ejecución
Otro uso habitual de los decoradores es para medir el tiempo de ejecución de las funciones. Para esto solamente se tiene que importar la librería time
, obtener la hora a la que se llama a la función y cuando termina para calcular el tiempo que ha tardado. Una posible implementación de esto es la que se muestra a continuación.
import time def medir_tiempo(funcion): def wrapper(*args, **kwargs): inicio = time.time() resultado = funcion(*args, **kwargs) fin = time.time() print(f"{funcion.__name__} se ejecutó en {fin - inicio} segundos.") return resultado return wrapper @medir_tiempo def mi_funcion(): # Simulamos una operación que toma tiempo time.sleep(2) mi_funcion()
mi_funcion se ejecutó en 2.005181312561035 segundos.
Al igual que en el ejemplo anterior, se podría sacar también por pantalla la forma en la que se ha llamado a la función.
Conclusiones
Los decoradores en Python son un recurso que permite simplificar la escritura de código. Cuando es necesario repetir una misma tarea en varias funciones, como puede ser la medida del tiempo de ejecución o mostrar información de las llamadas, se puede escribir un decorador en lugar de incluir este código dentro de las funciones. Manteniendo de esta manera el código más compacto y sencillo.
Image by Susanne Jutzeler, Schweiz 🇨🇭 suju-foto from Pixabay
Deja una respuesta