class: center, middle, inverse, title-slide .title[ #
Introducción a Python
] .subtitle[ ##
Clase 6d: Lambda functions y decoradores
] .author[ ### Daniel Miles Touya
Máster en Análisis de Datos · UdelaR-Uvigo
] .date[ ### 24 abril 2026 ] --- --- class: inverse, middle .huge[Clase 6d] <br> ## Lambda functions --- # Guía de lectura .smallest[ Hasta ahora: - funciones como objetos - funciones como argumentos ] -- .div_bloque[ Ahora: > funciones sin nombre ] --- # Qué es una lambda .div_bloque[ Una lambda es una función anónima. ] -- .smallest[ - sin nombre - en una sola línea - devuelve automáticamente ] --- # Sintaxis ```python lambda argumentos: expresion ``` -- .smallest[ Equivale a: ] ```python def f(x): return x * 2 ``` --- # Ejemplo ```python doble = lambda x: x * 2 print(doble(5)) ``` -- .smallest[ 10 ] --- # Sin asignar .smallest[ Uso directo: ] ```python print((lambda x, y: x + y)(3, 4)) ``` -- .smallest[ 7 ] --- # Idea clave .div_bloque[ Lambda = función rápida de un solo uso. ] --- # Diferencia con def .smallest[ Lambda: ] - una expresión - sin nombre (idealmente) -- .smallest[ def: ] - múltiples líneas - reutilizable --- # Condicional en lambda .smallest[ Solo expresión: ] ```python f = lambda x: "par" if x % 2 == 0 else "impar" print(f(3)) ``` --- # Error típico .div_bloque[ Intentar meter lógica compleja. ] -- ```python # ilegible lambda x: "alto" if x > 100 else "medio" if x > 50 else "bajo" ``` -- .div_bloque.small[ .hi-red[Problema:] difícil de leer → usar def ] --- # Cuándo usar lambda .div_bloque[ Cuando: ] -- .smallest[ - función simple - uso puntual - como argumento ] --- # Ejemplo clave (sorted) ```python pares = [(3, 2), (1, 7), (2, 4)] print(sorted(pares, key=lambda x: x[1])) ``` -- .smallest[ Ordena por segundo elemento. ] --- # Ejemplo (map) ```python numeros = [1, 2, 3] print(list(map(lambda x: x**2, numeros))) ``` --- # Ejemplo (filter) ```python numeros = [1, 2, 3, 4] print(list(filter(lambda x: x % 2 == 0, numeros))) ``` --- # Mini ejercicio 1 .smallest[ Reescribe como lambda: ] ```python def triple(x): return x * 3 ``` --- # Mini ejercicio 2 .smallest[ Predice: ] ```python f = lambda x, y: x if x > y else y print(f(3, 5)) ``` --- # Mini ejercicio 3 .smallest[ ¿Qué problema hay? ] ```python f = lambda x: x**2 if x > 0 else x**3 if x > -10 else 0 ``` --- # Mini ejercicio 4 .smallest[ ¿Cuál usarías? ] - ordenar lista → lambda o def - función usada en todo el código → lambda o def --- # Idea clave .div_bloque[ Lambda no sustituye a def. ] -- .div_bloque.small[ .hi-blue[Regla:] si es compleja → def si es simple → lambda ] --- # Leer código IA .div_bloque[ Cuando veas lambda: ] -- .smallest[ - identifica argumentos - identifica expresión - traduce a def mentalmente ] --- # Qué debes entender .smallest[ - qué es lambda - cuándo usarla - limitaciones - uso en sorted/map/filter ] -- .div_bloque[ .hi-blue[Idea final:] > Lambda es una función corta para uso inmediato. ] --- # Parte II · Decoradores class: inverse, middle .huge[Modificar funciones] <br> ## Decorators --- # Motivación .div_bloque[ Queremos modificar el comportamiento de una función. ] -- .smallest[ Sin cambiar su código. ] --- # Ejemplo problema .smallest[ Queremos añadir logging: ] ```python def saludar(): print("Hola") ``` -- .smallest[ Queremos: - imprimir antes - ejecutar función - imprimir después ] --- # Solución manual ```python def saludar(): print("Antes") print("Hola") print("Después") ``` -- .div_bloque.small[ Problema: no es reutilizable ] --- # Idea clave .div_bloque[ Una función que modifica otra función. ] --- # Paso 1 · función como argumento ```python def wrapper(func): def nueva(): print("Antes") func() print("Después") return nueva ``` --- # Paso 2 · usarla ```python def saludar(): print("Hola") saludar = wrapper(saludar) saludar() ``` -- .smallest[ Antes Hola Después ] --- # Qué ha pasado .div_bloque[ Hemos sustituido la función. ] --- # Definición .div_bloque[ Un decorador es una función que recibe una función y devuelve otra. ] --- # Sintaxis con @ .smallest[ Forma compacta: ] ```python @wrapper def saludar(): print("Hola") ``` -- .smallest[ Equivale a: ```python saludar = wrapper(saludar) ``` ] --- # Ejemplo completo ```python def decorador(func): def nueva(): print("Inicio") func() print("Fin") return nueva @decorador def mensaje(): print("Hola") mensaje() ``` --- # Mini ejercicio 1 .smallest[ Predice: ] ```python def deco(f): def nueva(): print("A") f() print("B") return nueva @deco def g(): print("X") g() ``` --- # Mini ejercicio 2 .smallest[ ¿Qué hace esto? ] ```python def deco(f): def nueva(): return f() * 2 return nueva @deco def h(): return 5 print(h()) ``` --- # Error típico .div_bloque[ Olvidar devolver la función. ] -- ```python def deco(f): def nueva(): f() ``` -- .div_bloque.small[ .hi-red[Problema:] devuelve None ] --- # Conexión con closures .div_bloque[ El decorador usa un closure. ] -- .smallest[ La función interna recuerda `func`. ] --- # Idea profunda .div_bloque[ Separamos comportamiento y lógica. ] --- # Uso real .smallest[ Muy común en: - logging - control de acceso - validación ] --- # Leer código IA .div_bloque[ Cuando veas @: ] -- .smallest[ - hay una función modificando otra - busca el decorador - entiende qué añade ] --- # Qué debes entender .smallest[ - qué es un decorador - cómo se construye - sintaxis @ - relación con funciones y closures ] -- .div_bloque[ .hi-blue[Idea final:] > Un decorador envuelve una función para modificar su comportamiento. ] --- # Parte III · Decoradores en la práctica class: inverse, middle .huge[Uso real] <br> ## Decorators avanzados --- # Problema .div_bloque[ Queremos decorar funciones con argumentos. ] -- .smallest[ Ejemplo: ] ```python def suma(a, b): return a + b ``` --- # Error típico .smallest[ Este decorador falla: ] ```python def deco(f): def nueva(): print("Inicio") f() print("Fin") return nueva ``` -- .div_bloque.small[ .hi-red[Problema:] no acepta argumentos ] --- # Solución .div_bloque[ Usar *args y **kwargs ] -- ```python def deco(f): def nueva(*args, **kwargs): print("Inicio") result = f(*args, **kwargs) print("Fin") return result return nueva ``` --- # Uso ```python @deco def suma(a, b): return a + b print(suma(2, 3)) ``` -- .smallest[ Inicio Fin 5 ] --- # Idea clave .div_bloque[ Decoradores reales siempre usan *args, **kwargs. ] --- # Decorador con argumentos .div_bloque[ Un decorador puede recibir parámetros. ] --- # Estructura .smallest[ Tres niveles: ] ```python def deco_param(x): def decorador(f): def nueva(*args, **kwargs): print("param:", x) return f(*args, **kwargs) return nueva return decorador ``` --- # Uso ```python @deco_param(10) def f(a): return a * 2 print(f(3)) ``` -- .smallest[ param: 10 6 ] --- # Mini ejercicio 1 .smallest[ Predice: ] ```python def deco(f): def nueva(*args): return f(*args) + 1 return nueva @deco def g(x): return x * 2 print(g(3)) ``` --- # Mini ejercicio 2 .smallest[ ¿Qué imprime? ] ```python def deco(f): def nueva(*args): print("call") return f(*args) return nueva @deco def f(x): return x + 1 f(5) ``` --- # Mini ejercicio 3 .smallest[ ¿Dónde está el error? ] ```python def deco(f): def nueva(*args): f(*args) return nueva ``` -- .div_bloque.small[ .hi-red[Problema:] no devuelve resultado ] --- # Uso real .smallest[ Decoradores aparecen en: - Flask (@app.route) - testing - logging - control de acceso ] --- # Ejemplo conceptual ```python @app.route("/home") def home(): return "Hola" ``` -- .smallest[ El decorador modifica la función. ] --- # Buenas prácticas .div_bloque[ Siempre: ] -- .smallest[ - usar *args, **kwargs - devolver el resultado - mantener funciones simples ] --- # Leer código IA .div_bloque[ Cuando veas decoradores: ] -- .smallest[ - identifica wrapper - mira qué añade - comprueba argumentos ] --- # Qué debes entender .smallest[ - decoradores con argumentos - uso de *args, **kwargs - errores típicos - patrones reales ] -- .div_bloque[ .hi-blue[Idea final:] > Los decoradores permiten extender funciones sin modificarlas. ]