Jose Francisco Romero Meza
Rhonal Velasco
Buen aporte
Axel Abel Tuchez López
Gracias, me ayudo a entender mejor
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?
if __name__ == "__main__":.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í?
@ sobre la función objetivo.wrapper vive dentro de password_required.return wrapper pertenece a la función decoradora, no a wrapper.¿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.* 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?
print dentro de la lógica principal.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?
¿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?
print y no return, su valor de retorno es None.upper() sobre None produce un error: “'NoneType' object has no attribute 'upper'”.print en el punto de uso.¿Cómo abordar mensajes de error y depuración?
¿Qué otras buenas prácticas se muestran?
wrapper en el decorador.if __name__ == "__main__".Te leo en los comentarios: ¿qué patrón con decoradores usarás primero y qué caso práctico te gustaría automatizar con Python?
Jose Francisco Romero Meza
Rhonal Velasco
Buen aporte
Axel Abel Tuchez López
Gracias, me ayudo a entender mejor
Jesús Maximiliano Manchuk
Información muy clara sobre args y kwargs:
Manuel Alejandro Aguilar Téllez Girón
¡¡¡Buenísimo aporte, gracias!!!
Alvez Gerardo
Excelente! clarisimo queda.
Ingrid Natalia Rodriguez Ovalle
Acá está explicado y con ejemplos simples: https://www.youtube.com/watch?v=DQXm6bIZgvk
Sergio Abel Gordon Dolimpio
Si, la verdad que mejor explicado, gracias
Daniel Paloma Murcia
Gracias por el aporte, está bien explicado y me suscribí al canal.
Facundo Nicolás García Martoni
ProfesorCarlos Vidal
Justo esa escena vino a mi cabeza jeje !
Milton Andrés Sanabria
Aquí hay un vídeo donde explican bien el tema de los decoradores: Decoradores - Codigo Facilito
Estos temas que cuestan un poco asimilarlos deberían ser explicados de la forma mas sencilla posible, ya teniendo claro el concepto se puede volver tan complejo como se requiera.
Jonathan Macalupu Reyes
Interesante, ayuda y refuerza la clase.
Hice un micro juego de texto:
def upper(func): def wrapper(*args, **kwargs): result = func(*args, **kwargs) return result.upper() return wrapper @upper def say_my_name(name): if name == 'Heisenberg': return 'Youre Goddamn Right' else: name = input('Say my name! ') say_my_name(name) if __name__ == '__main__': name = input('Now, say my name ') result = say_my_name(name) print(result)
juan david jaramillo zuñiga
les dejo este link: https://code.tutsplus.com/articles/understanding-args-and-kwargs-in-python--cms-29494 donde entenderán un poco más como usar args y kwargs en python. Súper útil.
Carlos Enrique Ramírez Flores
Gracias !
José Gallegos
Muy buen aporte, muchas gracias
Hugo Orlando Gonzalez
Me parece mucho más fácil entender los decoradores en Python que entender un callback en Javascript
Manuel Ledezma
x10000
Andrés Felipe Martínez Salazar
Dentro del wrapper de password_required se puede omitir el else debido a que dentro del if se ejecuta una sentencia return haciendo que en caso de cumplirse la condición lo que esta después de ella nunca se ejecuta.
juan cabrera
el else es para imprimir que es incorrecto el password
Andrés Felipe Martínez Salazar
@jjjericu me refiero a la sentencia else, lo que está dentro de esta se mantiene solo que se arregla la identacion.
Marcelo Sánchez
*args : le pasamos una cantidad indefinida de parámetros ( args es un nombre definido por convención, le puedes poner el que tu quieras ).
**kwargs : le pasamos una cantidad indefinida de parámetros, pero ahora con su respectiva clave ( o llave ), veamos un ejemplo:
def func(numero_1, numero_2): print(numero_1 + numero_2) func(numero_1 = 5, numero_2 = 3) # Vemos aqui que la llave es numero_1 y numero_2
Como vemos la sintaxis "numero_1 = 5" representa al parámetro con su respectiva clave, por eso se utiliza como convención "**kwargs" (te recuerdo que le puedes poner el nombre que quieras)
Roman Lopez Garro
Aca el link que habla sobre *args y **kwargs me parecio sencillo de entender
Roman Lopez Garro
Disculpen la mala redaccion jajaj, solo queria decir que la forma en que lo explicaba lo hacia de facil entendimiento, nada mas gente, saludos!
David Esteban Solorzano Taborda
Hay que tener en cuenta 2 cosas:
1 si la funcion que estamos decorando recibe parametros, es necesario los *args y **kwargs, de lo contrario no es necesario.
2 se puede crear otra funcion que encierre nuestro decorador, para pasarle parametros al decorador, osea podemos a Los decoradores cambiar el comportamiento con parametros propios.
Juan Diego Silva Garcia
Este tema es bastante “blows my mind” Cuando se tenga un poco de experiencia y necesiten un método para “encapsular” la lógica del llamado a la API de las contraseñas en el backend lo van a entender mejor y van a saber de la importancia.
Por eso David en el min 3:02 dice que desde main o desde el punto de entrada no se puede llamar a la función wrapper() agregando así una capa de seguridad a nuestra lógica de manejo de login's. Como ven el método main no se llama en ningun momento la función wrapper que contiene la lógica para acceder.
Edinson Requena
Les dejare por separado los scripts que hizo el profe con pequeños cambios
aca el primero:
PASSWORD = "hello123" def password_required(func): def wrapper(): password = input("What is the password? ") if password == PASSWORD: return func() else: print("The password is not correct") return wrapper @password_required def needs_password(): print("The password is correct, welcome") if __name__ == "__main__": needs_password()
y aca el segundo:
your_name = input("What is your name? ") def upper(func): def wrapper(*args, **kwargs): result = func(*args, **kwargs) return result.upper() return wrapper @upper def say_your_name(name): return f"Hola, {name}" if __name__ == '__main__': print (say_your_name(your_name))
Yelson Chevarrias Huaman
Consideren que los decoradores al retornar una función nueva esta no hereda las propiedades de la función original, para solucionar esto deben usar el decorador wraps del módulo functools, de esta manera las propiedades originales persisten.
from functools import wraps def decorador_sinwraps(func): def wrapper(*args, **kwargs): """Main wrapper | Decorador""" return func(*args, **kwargs) return wrapper def decorador_conwraps(func): @wraps(func) def wrapper(*args, **kwargs): """Main wrapper | Decorador""" return func(*args, **kwargs) return wrapper def func1(valor: int): """Función Quintuplicadora""" return valor * 5 @decorador_sinwraps def func2(valor: int): """Función Duplicadora""" return valor * 2 @decorador_conwraps def func3(valor: int): """Función Triplicadora""" return valor * 2 # Pruebas de persistencia de documentación. print(func1.__doc__) # Función Quintuplicadora # Se esperaría "Función Duplicadora" sin embargo resulta: print(func2.__doc__) # Main wrapper | Decorador # al usar wraps se "heredan" las propiedades de la función orginal: print(func3.__doc__) # Función Triplicadora
Victor Daniel Aguirre Gil
***args ** es para enviar tuplas como parametro a una función.
Podemos enviar esto:
func_args ('A', 'B', 'C', 'D', 'E')
y recibirlo así:
def func_args (n_arg, *args):
n args contiene el 1er elemento ‘A’
*args contiene la tupla (‘B’, ‘C’, ‘D’, ‘E’)
**kwargs es para enviar diccionarios como parametros a una función.
Podemos enviar esto:
func_kwargs(caricatura = 'batman', pelicula = 'KillBill', serie = 'BigBang')
y recibirlo así:
def func_kwargs(**kwargs):
**kwargs contiene el diccionario.
Mario Barbero Santillán
Alex Zambrano
Facundo Nicolás García Martoni
Profesor¡Hola @datalex! Te dejo este artículo muy bueno para complementar la explicación de args y kwargs de este curso ;)
Luis Kennedy Saavedra Fuentes
Andrés Felipe Mesa David
Quitale los parentesis al return del wrapper.
es solo return wrapper no wrapper()
Luis Kennedy Saavedra Fuentes
Gracias companero!!
DECORADORES EN PYTHON
Los decoradores sirven para ejecutar lógica del código antes y/o después de otra función, esto nos ayuda a generar funciones y código que pueda ser reutilizado fácilmente sin hacer más extenso nuestro código. Hay que recordar que si se genera una función dentro de otra solo existiera en ese scope(dentro de la función padre), si se quiere invocar una función varias veces dentro de otras se tiene que generar de manera global.
**args y kwargs**
Básicamente lo que hacen es pasar tal cual los valores de de los argumentos que se pasan a la función args hace referencias a listas y kwargs a elementos de un diccionario (llave: valor)
** args: **
def test_valor_arg(n_arg, *args): print('primer valor normal: ', n_arg) For arg in args: print('este es un valor de *args: ',arg) print(type(args)) if__name__ == '__main__': test_valor_args('carlos','Karla','Paola','Elena')
**kuargs: **
def test_valor_kwargs(**kwargs): if kwargs is not None: for key, value in kwargs.items(): print('%s == %s' %(key,value)) print(type(kwargs)) if __name__ == '__main__': test_valor_kwargs(caricatura='batman')
Este es un ejemplo usando los 2 en una función
def test_valor_kwargs_args(*args, **kwargs): print(type(kwargs)) print(kwargs) print('----------') print(type(args)) print(args) if __name__ == '__main__': test_valor_kwargs_args('flash', 'batman', caricatura='batman', empresa = 'dc')
Aplicando los args a un ejercicio simple
""" Definir una función max_de_tres(), que tome tres números como argumentos y devuelva el mayor de ellos. """ def max_number(n_arg, *args): #print('Primer valor normal: ', n_arg) for i in range(len(args)): if n_arg > args[i]: pass else: n_arg = args[i] #print('Este es el valor de *args: ', args[i]) return n_arg def max_number_2(number1, number2, number3): if number1 > number2: if number1 > number3: return number1 else: return number3 else: if number2 > number3: return number2 else: return number3 if __name__ == '__main__': number1 = None number2 = None number3 = None while not number1: number1 = input('What is the first number? ') while not number2: number2 = input('What is the second number? ') while not number3: number3 = input('What is the third number? ') print('-' * 30) print(max_number(number1, number2, number3)) print('-' * 30) print(max_number_2(number1, number2, number3)) print('-' * 30) print(max(number1, number2, number3)) # esta es la función max() que tiene incorporada python
Aquí dejo un ejemplo muy sencillo que usé para practicar decoradores. A pesar de lo sencillo me tomó bastante tiempo corregir la gran cantidad de errores que se prensentaron para completarlo, sobre todo al tratar de usar los **kwargs dentro del wrapper
"""Evalua si una persona esta en la lista de invitados""" import functools amigo = {'name':'Alex','lastname':'Zambrano'} GUESTS = [{'name':'Jose','lastname':'Perez'},{'name':'Pedro','lastname':'Sanchez'}] def invitado(func): @functools.wraps(func) def wrapper(*args,**kwargs): found = False for id,guest in enumerate(GUESTS): if guest['name'] == kwargs['name'] and guest['lastname'] == kwargs['lastname']: func(*args,**kwargs) found = True break if found == False: print('{} {} no se encuentra en la lista de invitados'.format(kwargs['name'],kwargs['lastname'])) return wrapper @invitado def generate_identification_card(**kwargs): print('La identificacion para {} {} ha sido generada'.format(kwargs['name'],kwargs['lastname'])) generate_identification_card(name=amigo['name'],lastname=amigo['lastname'])```
Me dice el siguiente error despuEs de imprimir el resultado:
c:\PYTHON\PYTHON>python decoradores.py Password: 12345 Password correct Traceback (most recent call last): File "decoradores.py", line 35, in <module> needs_password() TypeError: 'NoneType' object is not callable
PASSWORD = '12345' def password_required(func): def wrapper(): password = input('Password: ') if password == PASSWORD: return func() else: print('Password incorrect!') return wrapper() def upper_name(func): def wrapper(*args, **kwargs): result = func(*args, **kwargs) return result.upper() return wrapper @password_required def needs_password(): print('Password correct') @upper_name def print_name(name): return 'Hola {}'.format(name) if __name__ == '__main__': needs_password() #print(print_name('David'))