Scope de variables
Cuando escribís x = 10 dentro de una función, ¿es la misma x que la de afuera? No.
Python tiene reglas estrictas sobre dónde "vive" cada variable. Entender el scope te evita bugs invisibles y
te permite escribir funciones seguras.
Concepto teórico
¿Qué es el scope?
El scope (ámbito) de una variable es la zona del código donde esa variable es visible y
accesible. Cuando usás un nombre (x, saldo, print), Python busca en un
orden específico hasta encontrarlo. Si no lo encuentra en ningún nivel, da NameError.
La regla LEGB
Python busca nombres en este orden estricto (de más interno a más externo):
- L — Local: variables definidas DENTRO de la función actual
- E — Enclosing: variables de funciones externas (en funciones anidadas / closures)
- G — Global: variables definidas a nivel del módulo (fuera de toda función)
- B — Built-in: nombres integrados de Python (
print,len,range,True)
print = 42 en tu código, sobreescribís el
built-in print y ya no podés imprimir (¡no lo hagas!).Scope local — variables dentro de funciones
Cada función crea su propio scope local. Las variables definidas dentro de una función solo existen dentro de esa función. Cuando la función termina, desaparecen:
def calcular():
resultado = 42 # LOCAL a calcular()
return resultado
calcular()
# print(resultado) # NameError: resultado no existe acá afuera
Esto es una VENTAJA: cada función trabaja con sus propias variables sin interferir con el resto del programa. Es como oficinas privadas — lo que pasa adentro no afecta a las demás.
Scope global — variables del módulo
Las variables definidas fuera de toda función son globales. Se pueden LEER desde cualquier función, pero
NO se pueden MODIFICAR sin declarar global:
IVA = 0.21 # global
def con_iva(precio):
return precio * (1 + IVA) # ✅ LEER global: funciona
def cambiar_iva():
# IVA = 0.27 ← esto crea una LOCAL nueva, no modifica la global
global IVA # ← esto SÍ permite modificar la global
IVA = 0.27
global siempre que puedas. Las variables globales
mutables son una fuente de bugs porque cualquier función puede cambiarlas en cualquier momento. Es como tener
una planilla de Excel compartida sin control de cambios. Preferí pasar valores como parámetros y devolver
resultados con return.Nonlocal — closures y funciones anidadas
nonlocal permite que una función interna modifique variables de la función externa (scope
Enclosing). Se usa en closures con estado:
def crear_contador():
cuenta = 0 # scope Enclosing
def incrementar():
nonlocal cuenta # sin esto, Python crea una local nueva
cuenta += 1
return cuenta
return incrementar
cont = crear_contador()
print(cont()) # 1
print(cont()) # 2 — recuerda el estado
Errores comunes de scope
| Error | Causa | Solución |
|---|---|---|
UnboundLocalError |
Asignás a una variable que Python ya interpretó como local | Usá global o pasá como parámetro |
NameError |
La variable no existe en ningún scope | Verificá el nombre, ¿la definiste? |
| Sobreescribir built-in | list = [1,2] oculta list() |
Nunca uses nombres de built-ins |
| Mutación accidental | Modificar una lista global desde una función | Trabajá con copias o pasá explícitamente |
global es como editar el pizarrón directamente. nonlocal es como editar el
post-it de tu jefe directo. Lo ideal es que cada uno trabaje con sus propias notas y las comparta mediante
reportes (return).Ejemplos explicados paso a paso
Ejemplo 1: LEGB en acción
Hacé clic en ▶ Ejecutar
Ejemplo 2: El error UnboundLocalError
Hacé clic en ▶ Ejecutar
Ejemplo 3: nonlocal en closures con estado
Hacé clic en ▶ Ejecutar
Ejemplo 4: Peligro de sobreescribir built-ins
Hacé clic en ▶ Ejecutar
Ejemplo 5: Scope y mutabilidad — la trampa de las listas globales
Hacé clic en ▶ Ejecutar
Referencia rápida
| Scope | Dónde vive | Leer | Modificar |
|---|---|---|---|
| Local | Dentro de la función | Directo | Directo |
| Enclosing | Función externa (closure) | Directo | Con nonlocal |
| Global | Nivel del módulo | Directo | Con global |
| Built-in | Python interno | Directo | No (no lo hagas) |
| Buena práctica | Mala práctica |
|---|---|
| Pasar datos como parámetros | Leer variables globales dentro de funciones |
| Devolver resultados con return | Modificar globales con global |
| Trabajar con copias de listas/dicts | Mutar argumentos mutables silenciosamente |
| Usar nombres descriptivos | Sobreescribir built-ins (list, dict, type) |
Ejercicios
Ejercicio 1: Identificar scopes
Dado el código, predecí qué imprime ANTES de ejecutar. Después ejecutá para verificar. Debe incluir
local.
Hacé clic en ▶ Ejecutar
Ejercicio 2: Leer global desde función
Definí IVA = 0.21 como global. Creá una función con_iva(precio) que la USE (sin
global). Debe incluir 12100.
Hacé clic en ▶ Ejecutar
Ejercicio 3: UnboundLocalError
Reproducí el error UnboundLocalError y después arreglalo pasando el valor como parámetro. Debe
incluir 150000.
Hacé clic en ▶ Ejecutar
Ejercicio 4: Global keyword
Creá un contador global operaciones = 0 y una función registrar() que lo incremente
con global. Llamala 5 veces e imprimí. Debe incluir 5.
Hacé clic en ▶ Ejecutar
Ejercicio 5: Nonlocal en closure
Creá un closure crear_acumulador() que devuelva una función agregar(monto) que
acumule un total con nonlocal. Debe incluir 300.
Hacé clic en ▶ Ejecutar
Ejercicio 6: Evitar sobreescribir built-ins
Corregí este código que sobreescribe list y sum. Después usá los verdaderos
list() y sum(). Debe incluir 15.
Hacé clic en ▶ Ejecutar
Ejercicio 7: Función pura vs impura
Creá una versión "impura" (modifica global) y una "pura" (parámetro + return) de una función que aplique
descuento a un precio. La pura debe devolver el resultado sin modificar nada. Debe incluir 8500.
Hacé clic en ▶ Ejecutar
Ejercicio 8: Scope en comprehensions
Las variables de for en list comprehensions tienen scope local (Python 3+). Demostralo: creá
x = "global", después resultado = [x for x in range(5)], e imprimí x
para ver que sigue siendo "global". Debe incluir global.
Hacé clic en ▶ Ejecutar
Ejercicio 9: Closure con scope aislado
Creá una fábrica de funciones crear_filtro(umbral) que devuelva una función que filtre elementos
mayores al umbral de una lista. Creá dos filtros con umbrales distintos. Debe incluir [890000].
Hacé clic en ▶ Ejecutar
Ejercicio 10: Mini sistema bancario con closures
Creá crear_cuenta(titular, saldo_inicial) que devuelva 3 funciones:
depositar(monto), extraer(monto) y consultar(). Usá
nonlocal para manejar el saldo. Probá con operaciones. Debe incluir Saldo:.
Hacé clic en ▶ Ejecutar
Resumen y conexión
- Python busca variables en orden LEGB: Local → Enclosing → Global → Built-in.
- Variables locales solo existen dentro de su función. Al terminar, desaparecen.
globalpermite modificar una global desde una función. Evitalo siempre que puedas.nonlocalpermite modificar variables del scope Enclosing (closures).- NUNCA sobreescribas built-ins (
list,dict,type,id,sum). - Funciones puras (parámetro → return) son más seguras que funciones que mutan globales.
En la siguiente lección (23 · Strings avanzado) vas a profundizar en slicing, regex con
re, encoding UTF-8 y patrones avanzados de procesamiento de texto.
Recursos: Python docs — Scopes