class: center, middle, inverse, title-slide .title[ #
Introducción a Python
] .subtitle[ ##
Clase 6c: Funciones de Primera Clase
] .author[ ### Daniel Miles Touya
Máster en Análisis de Datos · UdelaR-Uvigo
] .date[ ### 24 abril 2026 ] --- --- class: inverse, middle .huge[Clase 6c] <br> ## Funciones como objetos --- # Guía de lectura .smallest[ Hasta ahora: - sabemos definir funciones - sabemos usarlas ] -- .div_bloque[ Ahora cambia el paradigma: > las funciones son datos ] --- # Idea clave .div_bloque[ Las funciones son objetos. ] -- .smallest[ Igual que: - números - listas - strings ] --- # Ejemplo ```python def square(x): return x * x print(type(square)) ``` -- .smallest[ <class 'function'> ] --- # Propiedades de objeto .smallest[ Las funciones tienen: ] ```python print(square.__name__) print(id(square)) print(dir(square)) ``` -- .smallest[ Como cualquier objeto. ] --- # Nombre vs objeto .div_bloque[ El nombre NO es la función. ] -- .smallest[ El nombre apunta al objeto. ] --- ```python def square(x): return x * x f = square print(f(5)) print(f is square) ``` -- .smallest[ 25 True ] --- # Diferencia clave .smallest[ Comparar: ] ```python f = square # función g = square(5) # resultado ``` -- .div_bloque.small[ .hi-red[MUY importante:] paréntesis → ejecuta sin paréntesis → objeto ] --- # Borrar el nombre ```python def square(x): return x * x f = square del square print(f(5)) ``` -- .smallest[ La función sigue existiendo. ] --- # Idea profunda .div_bloque[ El objeto vive independientemente del nombre. ] --- # Mini ejercicio 1 .smallest[ Predice: ] ```python def doble(x): return x * 2 g = doble print(g) print(g(5)) print(type(g)) ``` --- # Mini ejercicio 2 .smallest[ ¿Qué diferencia hay? ] ```python a = doble b = doble(3) print(type(a)) print(type(b)) ``` --- # Por qué importa .div_bloque[ Esto permite: ] -- .smallest[ - guardar funciones - pasarlas como argumentos - devolver funciones ] --- # Idea final class: center, middle .huge[Una función es un objeto que puedes usar como dato] --- # Parte II · Funciones como argumentos class: inverse, middle .huge[Separar el qué del cómo] <br> ## Funciones como input --- # Idea clave .div_bloque[ Podemos pasar funciones como argumentos. ] -- .smallest[ Igual que números o listas. ] --- # Motivación .smallest[ Código repetido: ] ```python numeros = [1, 2, 3] res = [] for n in numeros: res.append(n * 2) ``` -- .smallest[ ¿Y si cambia la operación? ] --- # Problema .smallest[ Repetimos el mismo patrón: ] ```python # cuadrados # cubos # raíces ``` -- .div_bloque[ Solo cambia la operación. ] --- # Solución .div_bloque[ Pasar la operación como argumento. ] --- # Ejemplo ```python def cuadrado(x): return x**2 def my_map(func, lista): res = [] for x in lista: res.append(func(x)) return res ``` --- # Uso ```python numeros = [1, 2, 3] print(my_map(cuadrado, numeros)) ``` -- .smallest[ [1, 4, 9] ] --- # Idea clave .div_bloque[ La función no sabe qué hace `func`. ] -- .smallest[ Solo la ejecuta. ] --- # Ejemplo con built-in ```python print(my_map(len, ["hola", "python"])) ``` -- .smallest[ [4, 6] ] --- # Ejemplo más general .smallest[ Función matemática: ] ```python def derivada(f, x, h=1e-5): return (f(x+h) - f(x)) / h ``` --- # Uso ```python def cuadrado(x): return x**2 print(derivada(cuadrado, 3)) ``` -- .smallest[ ≈ 6 ] --- # Idea profunda .div_bloque[ Separas: - el algoritmo - la función concreta ] --- # Mini ejercicio 1 .smallest[ Predice: ] ```python def aplicar(func, x): return func(x) print(aplicar(abs, -5)) print(aplicar(str, 10)) ``` --- # Mini ejercicio 2 .smallest[ ¿Qué imprime? ] ```python def f(x): return x + 1 def g(x): return x * 2 funciones = [f, g] for fun in funciones: print(fun(3)) ``` --- # Mini ejercicio 3 .smallest[ ¿Qué error hay? ] ```python def suma(a, b): return a + b print(my_map(suma, [1, 2, 3])) ``` -- .div_bloque.small[ .hi-red[Problema:] firma incorrecta ] --- # Patrón real .div_bloque[ Esto aparece en: ] -- .smallest[ - map() - sorted(key=...) - pandas.apply() ] --- # Leer código IA .div_bloque[ Cuando veas esto: ] ```python df.apply(func) ``` -- .smallest[ → func se aplica a cada elemento ] --- # Qué debes entender .smallest[ - funciones como argumentos - separación lógica - patrón map - errores de firma ] -- .div_bloque[ .hi-blue[Idea final:] > Pasar funciones permite escribir código general. ] --- # Parte III · Fábricas y closures class: inverse, middle .huge[Funciones que crean funciones] <br> ## Closures --- # Motivación .div_bloque[ ¿Y si una función devuelve otra función? ] -- .smallest[ Esto es posible porque las funciones son objetos. ] --- # Ejemplo básico ```python def crear_sumador(n): def suma(x): return x + n return suma ``` --- # Uso ```python sumar_5 = crear_sumador(5) print(sumar_5(10)) ``` -- .smallest[ 15 ] --- # Qué está pasando .div_bloque[ La función “recuerda” n. ] -- .smallest[ Aunque crear_sumador ya terminó. ] --- # Closure .div_bloque[ Un closure es una función que recuerda su entorno. ] --- # Ejemplo paso a paso .smallest[ 1. se llama crear_sumador(5) 2. se crea suma(x) 3. suma “recuerda” n = 5 4. se devuelve suma ] --- # Otro ejemplo ```python def multiplicador(k): def f(x): return x * k return f ``` --- # Uso ```python por_3 = multiplicador(3) print(por_3(4)) ``` -- .smallest[ 12 ] --- # Idea clave .div_bloque[ Cada llamada crea una función distinta. ] --- # Mini ejercicio 1 .smallest[ Predice: ] ```python f1 = crear_sumador(2) f2 = crear_sumador(10) print(f1(5)) print(f2(5)) ``` --- # Mini ejercicio 2 .smallest[ ¿Qué imprime? ] ```python def f(n): def g(x): return x * n return g h = f(3) print(h(2)) ``` --- # Mini ejercicio 3 .smallest[ ¿Son iguales? ] ```python f1 = crear_sumador(5) f2 = crear_sumador(5) print(f1 == f2) ``` -- .div_bloque.small[ .hi-blue[Idea:] mismo comportamiento ≠ mismo objeto ] --- # Error típico .div_bloque[ Pensar que n desaparece. ] -- .smallest[ No desaparece → queda en el closure. ] --- # Cuándo se usa .smallest[ - funciones parametrizadas - configuración de modelos - callbacks ] --- # Conexión con IA .div_bloque[ Mucho código usa closures. ] -- .smallest[ Ejemplo: - funciones que dependen de parámetros - pipelines dinámicos ] --- # Leer código .div_bloque[ Cuando veas esto: ] ```python def outer(...): def inner(...): ... return inner ``` -- .smallest[ → es una fábrica de funciones ] --- # Qué debes entender .smallest[ - funciones que devuelven funciones - qué es un closure - cómo se “recuerda” el entorno ] -- .div_bloque[ .hi-blue[Idea final:] > Un closure es una función con memoria. ] --- # Parte IV · Paradigma funcional class: inverse, middle .huge[Otra forma de pensar] <br> ## Functional programming --- # Idea general .div_bloque[ Programar como composición de funciones. ] -- .smallest[ En lugar de: - pasos secuenciales ] -- .smallest[ Pensamos en: - transformaciones de datos ] --- # Comparación .smallest[ Estilo imperativo: ] ```python res = [] for x in [1, 2, 3]: res.append(x * 2) ``` -- .smallest[ Estilo funcional: ] ```python res = [x * 2 for x in [1, 2, 3]] ``` --- # Funciones puras .div_bloque[ Una función pura: ] -- .smallest[ - depende solo de sus inputs - no modifica el exterior ] --- # Ejemplo ```python def cuadrado(x): return x**2 ``` -- .smallest[ Siempre mismo output → mismo input ] --- # Función no pura ```python total = 0 def suma(x): global total total += x ``` -- .div_bloque.small[ .hi-red[Problema:] depende del estado externo ] --- # Ventajas .smallest[ - más fácil de entender - más fácil de testear - menos errores ] --- # Composición de funciones .div_bloque[ Combinar funciones. ] -- ```python def doble(x): return x * 2 def suma1(x): return x + 1 print(doble(suma1(3))) ``` --- # Map .smallest[ Aplicar función a datos: ] ```python list(map(lambda x: x * 2, [1, 2, 3])) ``` -- .smallest[ Equivalente a comprehension. ] --- # Lambda .div_bloque[ Funciones pequeñas sin nombre. ] -- ```python lambda x: x * 2 ``` -- .smallest[ Uso típico: ] ```python sorted([3, 1, 2], key=lambda x: x) ``` --- # Patrón general .div_bloque[ Datos → función → resultado ] -- .smallest[ Encadenado: ] ```python res = list(map(lambda x: x * 2, datos)) ``` --- # Mini ejercicio 1 .smallest[ Reescribe con comprehension: ] ```python list(map(lambda x: x + 1, [1, 2, 3])) ``` --- # Mini ejercicio 2 .smallest[ Predice: ] ```python def f(x): return x + 1 def g(x): return x * 2 print(g(f(3))) ``` --- # Mini ejercicio 3 .smallest[ ¿Qué problema hay? ] ```python x = 10 def f(y): return x + y ``` -- .smallest[ Depende de variable externa. ] --- # Conexión con IA .div_bloque[ Mucho código sigue este estilo. ] -- .smallest[ - transformaciones - pipelines - funciones encadenadas ] --- # Qué debes entender .smallest[ - qué es programación funcional - funciones puras - composición - uso de lambda ] -- .div_bloque[ .hi-blue[Idea final:] > Programar es transformar datos usando funciones. ]