Introducción

Los decoradores en Python son una herramienta poderosa que permite modificar el comportamiento de una función o método sin cambiar su código. Los decoradores son funciones que envuelven otra función, permitiendo ejecutar código antes y después de la función decorada sin modificar su estructura.

Conceptos Clave

  • Función Decoradora: Una función que toma otra función como argumento y extiende su comportamiento.
  • Función Decorada: La función original que se pasa a la función decoradora.
  • Sintaxis de Decoradores: Utiliza el símbolo @ seguido del nombre de la función decoradora antes de la definición de la función decorada.

Ejemplo Básico de Decorador

Definición de un Decorador

def mi_decorador(func):
    def envoltura():
        print("Algo se está haciendo antes de la función.")
        func()
        print("Algo se está haciendo después de la función.")
    return envoltura

Uso del Decorador

@mi_decorador
def di_hola():
    print("¡Hola!")

di_hola()

Explicación

  1. Definición del Decorador: mi_decorador es una función que toma otra función func como argumento y define una función interna envoltura que extiende el comportamiento de func.
  2. Uso del Decorador: El decorador se aplica a di_hola usando la sintaxis @mi_decorador. Esto es equivalente a di_hola = mi_decorador(di_hola).
  3. Ejecución: Cuando di_hola se llama, en realidad se ejecuta envoltura, que imprime mensajes antes y después de llamar a func.

Decoradores con Argumentos

Los decoradores también pueden aceptar argumentos. Para lograr esto, se necesita una capa adicional de funciones.

Ejemplo de Decorador con Argumentos

def repetir(n):
    def decorador(func):
        def envoltura(*args, **kwargs):
            for _ in range(n):
                func(*args, **kwargs)
        return envoltura
    return decorador

Uso del Decorador con Argumentos

@repetir(3)
def di_adios():
    print("¡Adiós!")

di_adios()

Explicación

  1. Definición del Decorador con Argumentos: repetir es una función que toma un argumento n y devuelve un decorador.
  2. Decorador Interno: El decorador interno decorador toma la función func y define envoltura que llama a func n veces.
  3. Uso del Decorador: @repetir(3) aplica el decorador a di_adios, haciendo que se ejecute tres veces cuando se llama.

Decoradores para Métodos de Clase

Los decoradores también pueden aplicarse a métodos de clase. Un uso común es el decorador @staticmethod y @classmethod.

Ejemplo de Decorador para Métodos de Clase

class MiClase:
    @staticmethod
    def metodo_estatico():
        print("Este es un método estático.")

    @classmethod
    def metodo_de_clase(cls):
        print(f"Este es un método de clase de {cls}.")

MiClase.metodo_estatico()
MiClase.metodo_de_clase()

Explicación

  1. Método Estático: @staticmethod indica que metodo_estatico no recibe una referencia a la instancia (self) ni a la clase (cls).
  2. Método de Clase: @classmethod indica que metodo_de_clase recibe una referencia a la clase (cls).

Ejercicios Prácticos

Ejercicio 1: Decorador de Tiempo de Ejecución

Crea un decorador que mida y muestre el tiempo de ejecución de una función.

import time

def medir_tiempo(func):
    def envoltura(*args, **kwargs):
        inicio = time.time()
        resultado = func(*args, **kwargs)
        fin = time.time()
        print(f"Tiempo de ejecución: {fin - inicio} segundos")
        return resultado
    return envoltura

@medir_tiempo
def dormir():
    time.sleep(2)

dormir()

Ejercicio 2: Decorador de Registro

Crea un decorador que registre el nombre de la función y los argumentos con los que fue llamada.

def registrar(func):
    def envoltura(*args, **kwargs):
        print(f"Llamando a {func.__name__} con {args} y {kwargs}")
        return func(*args, **kwargs)
    return envoltura

@registrar
def sumar(a, b):
    return a + b

print(sumar(3, 5))

Soluciones

Solución al Ejercicio 1

import time

def medir_tiempo(func):
    def envoltura(*args, **kwargs):
        inicio = time.time()
        resultado = func(*args, **kwargs)
        fin = time.time()
        print(f"Tiempo de ejecución: {fin - inicio} segundos")
        return resultado
    return envoltura

@medir_tiempo
def dormir():
    time.sleep(2)

dormir()

Solución al Ejercicio 2

def registrar(func):
    def envoltura(*args, **kwargs):
        print(f"Llamando a {func.__name__} con {args} y {kwargs}")
        return func(*args, **kwargs)
    return envoltura

@registrar
def sumar(a, b):
    return a + b

print(sumar(3, 5))

Conclusión

Los decoradores son una herramienta poderosa en Python que permite modificar el comportamiento de funciones y métodos de manera flexible y reutilizable. Entender cómo funcionan y cómo aplicarlos te permitirá escribir código más limpio y eficiente. En el siguiente tema, exploraremos los generadores, otra característica avanzada de Python que facilita la creación de iteradores.

Curso de Programación en Python

Módulo 1: Introducción a Python

Módulo 2: Estructuras de Control

Módulo 3: Funciones y Módulos

Módulo 4: Estructuras de Datos

Módulo 5: Programación Orientada a Objetos

Módulo 6: Manejo de Archivos

Módulo 7: Manejo de Errores y Excepciones

Módulo 8: Temas Avanzados

Módulo 9: Pruebas y Depuración

Módulo 10: Desarrollo Web con Python

Módulo 11: Ciencia de Datos con Python

Módulo 12: Proyecto Final

© Copyright 2024. Todos los derechos reservados