Creación de decoradores en Python paso a paso

Clase 34 de 49Curso Práctico de Python: Creación de un CRUD

Resumen

Domina los decoradores en Python con un enfoque claro y práctico. Verás cómo proteger el acceso a funciones con una contraseña y cómo transformar resultados reutilizando lógica con un patrón profesional. La clave: entender el flujo con funciones anidadas, el uso de @ y el manejo de valores de retorno.

¿Cómo proteger una función con un decorador de contraseña?

Un decorador permite ejecutar lógica antes o después de una función. Aquí se usa para control de acceso con una constante de contraseña y el input del usuario.

¿Cuál es la estructura base del punto de entrada y la función?

  • Definir el punto de entrada con if __name__ == "__main__":.
  • Declarar una función a proteger que imprime un mensaje.
  • Usar una constante para la contraseña. En un entorno real se mencionó el hashing, pero aquí basta con una constante didáctica.
PASSWORD = "12345"

def needs_password():
    print("La contraseña es correcta.")

def password_required(func):
    def wrapper():
        pwd = input("¿Cuál es tu contraseña? ")
        if pwd == PASSWORD:
            return func()
        else:
            print("La contraseña no es correcta.")
    return wrapper

@password_required
def needs_password():
    print("La contraseña es correcta.")

if __name__ == "__main__":
    needs_password()

¿Qué conceptos clave aplicar aquí?

  • Decorador: se declara con @ sobre la función objetivo.
  • Función anidada y scope: wrapper vive dentro de password_required.
  • Convención wrapper: la función interna suele llamarse así.
  • Indentación: el return wrapper pertenece a la función decoradora, no a wrapper.
  • Control de acceso: si la contraseña falla, la función protegida no se ejecuta.

¿Qué cambia cuando la función decorada recibe parámetros?

Cuando la función tiene parámetros, el decorador usa args y kwargs para no atarse a una firma específica. Además, si transformas el resultado (por ejemplo, con upper), la función decorada debe devolver un valor.

¿Cómo aplicar args y kwargs en el wrapper?

  • *args: captura argumentos posicionales.
  • **kwargs: captura argumentos con nombre.
  • La “expansión” con * y ** pasa los argumentos originales a la función decorada.
def upper(func):
    def wrapper(*args, **kwargs):
        resultado = func(*args, **kwargs)
        return resultado.upper()
    return wrapper

¿Cómo se prepara la función decorada para ser transformada?

  • Evitar print dentro de la lógica principal.
  • Usar return para que el decorador reciba el valor y pueda modificarlo.
@upper
def say_my_name(nombre):
    return f"Hola, {nombre}"

if __name__ == "__main__":
    print(say_my_name("David"))  # Hola, DAVID

¿Qué método de string se usa para la transformación?

  • upper: método de string que convierte el texto a mayúsculas.
  • Se aplica al resultado que regresa la función decorada.

¿Qué errores comunes y buenas prácticas resalta el instructor?

Comprender el flujo evita fallas típicas y hace más legible el código, una habilidad esencial cuando usas funciones de terceros la mayor parte del tiempo.

¿Por qué return importa más que print en decoradores?

  • Si la función decorada hace print y no return, su valor de retorno es None.
  • Llamar upper() sobre None produce un error: “'NoneType' object has no attribute 'upper'”.
  • Solución: devolver el valor y dejar el print en el punto de uso.

¿Cómo abordar mensajes de error y depuración?

  • Leer el mensaje e inferir el objeto y el método en conflicto.
  • Si el mensaje es críptico, buscar el texto del error en Google.
  • Verificar valores de retorno y flujos condicionales.

¿Qué otras buenas prácticas se muestran?

  • Usar constantes para configuraciones como contraseñas.
  • Cuidar la indentación al retornar el wrapper en el decorador.
  • Entender el punto de entrada con if __name__ == "__main__".
  • Reutilizar lógica con decoradores para seguridad y transformación.
  • Leer código como hábito: los decoradores aparecen en web, command line y data science.

Te leo en los comentarios: ¿qué patrón con decoradores usarás primero y qué caso práctico te gustaría automatizar con Python?