class: center, middle, inverse, title-slide .title[ #
Introducción a Python
] .subtitle[ ##
Clase 6b: Funciones: Scope
] .author[ ### Daniel Miles Touya
Máster en Análisis de Datos · UdelaR-Uvigo
] .date[ ### 27 abril 2026 ] --- class: inverse, middle .huge[Clase 6b] <br> ## Scope (ámbito de variables) --- # Guía de lectura .smallest[ Hasta ahora: - sabemos definir funciones - sabemos usar variables ] -- .div_bloque[ Problema nuevo: > ¿por qué algunas variables “no existen” fuera de un <b>ambito</b>? ] --- # Ejemplo clave ```python def area(radio): pi = 3.14 return pi * radio**2 area(5) print(pi) # error print(radio) # error ``` -- .div_bloque[ NameError ] --- # Qué es el scope .div_bloque[ El scope determina: - dónde puedes usar una variable - cuándo existe ] --- # Dos dimensiones .smallest[ 1. DÓNDE (espacio) 2. CUÁNDO (tiempo) ] --- # Dónde (visibilidad) ```python x = 10 def f(): y = 20 print(x) # ok print(y) # ok f() print(x) # ok print(y) # error ``` --- # Cuándo (existencia) ```python def g(): z = 30 print(z) g() print(z) # error ``` -- .div_bloque.small[ z solo existe dentro de la función ] --- # Idea clave .div_bloque[ Las variables no existen siempre. ] -- .div_bloque.small[ .hi-red[MUY importante:] nacen y mueren durante la ejecución ] --- # Mini ejercicio 1 .smallest[ Predice el resultado: ] ```python def f(): x = 5 return x print(f()) print(x) ``` -- .smallest[ Pregunta: - ¿qué línea falla? ] --- # Mini ejercicio 2 .smallest[ ¿Por qué imprime siempre 1? ] ```python def contador(): n = 0 n += 1 print(n) contador() contador() contador() ``` --- # Idea clave .div_bloque[ Cada llamada crea sus propias variables. ] --- # Qué debes entender .smallest[ - qué es scope - dónde existe una variable - cuándo existe - por qué aparecen NameError ] -- .div_bloque[ .hi-blue[Idea final:] > El scope controla la vida de las variables. ] --- # Local and Global Scope > Dónde vive cada variable -- > Scope global >>.div_bloque[ Variables definidas fuera de funciones. ] -- ```python x = 10 def f(): print(x) f() ``` -- > .smallest[ Se puede leer desde dentro. ] --- # Idea clave .div_bloque[ Una función puede LEER variables globales. ] --- # Scope local > Local scope >>.div_bloque[ Variables dentro de una función. ] -- ```python def f(): y = 20 print(y) f() print(y) # error ``` -- .smallest[ No existen fuera. ] --- # Regla fundamental .div_bloque[ Asignar dentro de una función crea una variable local. ] --- # Ejemplo clave ```python x = "global" def f(): x = "local" print(x) f() print(x) ``` -- .smallest[ local global ] --- # Error típico (MUY importante) ```python x = 10 def f(): print(x) x = 5 ``` -- .div_bloque.small[ .hi-red[Error:] UnboundLocalError ] -- > Por qué ocurre >> .div_bloque[ Python detecta asignación → trata la variable como local. ] -- >> .smallest[ Incluso antes de la asignación. ] --- # Explicación .smallest[ En esta función: - `x` es local - pero se usa antes de tener valor ] --- # Mini ejercicio 1 .smallest[ Predice: ] ```python x = 100 def f(): print(x) f() ``` -- .smallest[ ¿Qué imprime? ] --- # Mini ejercicio 2 .smallest[ Predice: ] ```python x = 100 def f(): x = 50 print(x) f() print(x) ``` --- # Mini ejercicio 3 (clave) .smallest[ Predice el error: ] ```python total = 10 def suma(n): total = total + n return total suma(5) ``` --- # Cómo corregir (bien) .div_bloque[ No usar global → pasar argumentos ] -- ```python def suma(total, n): return total + n total = suma(total, 5) ``` --- # global (cuidado) .smallest[ Existe, pero evitar: ] ```python total = 10 def suma(n): global total total += n suma = suma(3) print(total) ``` -- .div_bloque.small[ .hi-red[Problema:] efectos laterales: `total` fue modificado ] --- # Uso correcto de global .div_bloque[ Solo para constantes (lectura) ] -- ```python IVA = 0.21 def precio(x): return x * (1 + IVA) ``` --- # Mini ejercicio 4 .smallest[ ¿Por qué esto funciona? ] ```python IVA = 0.21 def f(x): return x * IVA ``` -- .smallest[ Pero esto no: ] ```python IVA = 0.21 def f(x): IVA = IVA + 0.01 ``` --- # Idea clave .div_bloque[ Leer global → OK Modificar global → peligro ] --- # Qué debes entender .smallest[ - diferencia local vs global - regla de asignación - UnboundLocalError - cómo evitar errores ] -- .div_bloque[ .hi-blue[Idea final:] > Dentro de una función, asignar crea una variable local. ] --- # Regla LEGB **Cómo Python busca variables** -- > Motivación >> .div_bloque[Cuando usas una variable: ¿de dónde sale? ] -- <br> > .hi_blue[Regla LEGB] >>.div_bloque[ Python busca en este orden: .smallest[ 1. Local 2. Enclosing 3. Global 4. Built-in ] ] --- # L · Local .smallest[ Variables dentro de la función. ] ```python def f(): x = 10 print(x) f() ``` --- # E · Enclosing .smallest[ Funciones dentro de funciones. ] ```python def exterior(): x = 20 def interior(): print(x) interior() exterior() ``` -- .smallest[ Busca en el entorno exterior. ] --- # G · Global .smallest[ Variables definidas fuera. ] ```python x = 30 def f(): print(x) f() ``` --- # B · Built-in .smallest[ Funciones de Python. ] ```python print(len([1, 2, 3])) ``` -- .smallest[ `len`, `print`, etc. ] --- # Ejemplo completo ```python x = "global" def f(): x = "local" print(x) f() ``` -- .smallest[ Resultado: local ] --- # Ejemplo con enclosing ```python def exterior(): x = "enclosing" def interior(): print(x) interior() exterior() ``` -- .smallest[ Resultado: enclosing ] --- # Mini ejercicio 1 .smallest[ Predice: ] ```python x = "global" def f(): print(x) f() ``` --- # Mini ejercicio 2 .smallest[ Predice: ] ```python x = "global" def f(): x = "local" def g(): print(x) g() f() ``` --- # Mini ejercicio 3 .smallest[ Predice: ] ```python x = "global" def f(): def g(): print(x) g() f() ``` --- # Error típico .div_bloque[ Confundir de dónde viene la variable. ] -- .smallest[ Especialmente con funciones anidadas. ] --- # nonlocal (idea básica) .smallest[ Permite modificar variables enclosing. ] ```python def exterior(): x = 10 def interior(): nonlocal x x += 1 interior() print(x) ``` -- .smallest[ Resultado: 11 ] --- # Idea clave .div_bloque[ Python sigue un orden estricto. ] -- .div_bloque.small[ .hi-blue[LEGB] > Local → Enclosing → Global → Built-in ] --- # Qué debes entender .smallest[ - qué es LEGB - orden de búsqueda - funciones anidadas - de dónde vienen las variables ] -- .div_bloque[ .hi-blue[Idea final:] > Python busca variables siguiendo una jerarquía fija. ] --- # Frames, stack y heap .small[.hi-blue[Cómo se ejecuta el código]] > Modelo mental de Python >> .div_bloque[ ¿Qué pasa realmente cuando ejecutamos una función? ] -- .smallest[ Necesitamos un modelo mental. ] -- > Dos componentes .div_bloque[ >> Python usa: >>> Stack (pila de ejecución) >>>Heap (memoria de objetos) ] --- # Heap .div_bloque[ Aquí viven los objetos. ] -- .smallest[ Ejemplos: - listas - diccionarios - números ] -- ```python x = [1, 2, 3] ``` --- # Stack .div_bloque[ Aquí viven las funciones en ejecución. ] -- .smallest[ Cada llamada crea un frame. ] --- # Qué es un frame .div_bloque[ Un frame es el contexto de ejecución de una función. ] -- .smallest[ Incluye: - variables locales - argumentos - posición en el código ] --- # Ejemplo básico ```python def f(x): y = x + 1 return y f(5) ``` -- .smallest[ Se crea un frame para `f`. ] --- # Visualización mental .smallest[ Stack: - frame de `f` ] .smallest[ Heap: - objeto `5` - objeto `6` ] --- # Llamadas anidadas ```python def f(x): return g(x) def g(x): return x + 1 f(5) ``` -- .smallest[ Stack: - frame de f - frame de g ] -- > Orden de ejecución >> .div_bloque[ Last In, First Out (LIFO) ] -- >> .smallest[ Primero entra g → primero sale g ] --- # Ejemplo paso a paso .smallest[ 1. se llama f 2. f llama g 3. g devuelve valor 4. f termina ] --- # Variables locales .div_bloque[ Viven dentro del frame. ] -- .smallest[ Cuando termina la función: > desaparecen ] --- # Mini ejercicio 1 .smallest[ ¿Cuántos frames hay? ] ```python def f(x): return x + 1 f(5) ``` --- # Mini ejercicio 2 .smallest[ ¿Cuántos frames? ] ```python def f(x): return g(x) def g(x): return h(x) def h(x): return x + 1 f(5) ``` --- # Mini ejercicio 3 .smallest[ ¿Dónde vive esta lista? ] ```python def f(): x = [1, 2, 3] return x ``` -- .smallest[ - frame → variable `x` - heap → lista ] --- # Error típico .div_bloque[ Confundir variable con objeto. ] -- .smallest[ La variable está en el frame El objeto está en el heap ] --- # Idea clave .div_bloque[ Las funciones crean contextos independientes. ] -- .div_bloque.small[ .hi-blue[Idea:] > cada llamada = nuevo frame ] --- # Qué debes entender .smallest[ - qué es un frame - qué es el stack - qué es el heap - dónde viven las variables ] -- .div_bloque[ .hi-blue[Idea final:] > Python ejecuta funciones creando y destruyendo frames. ]