PyDA Course
📖 Lección 12 Principiante ⏱ 12 minutos ⚡ +10 XP ColabKagglenbviewerBinderDeepnoteGitHub alcance · global · lambda · sorted · map · filter

Alcance y lambdas

Comprende el alcance de las variables y escribe funciones en línea concisas.

🎯 Lo que aprenderás:
  • Comprender el alcance local frente al global
  • Usar las palabras clave global y nonlocal
  • Escribir funciones lambda para operaciones cortas
  • Aplicar lambdas con sorted(), map(), filter()

¿Dónde vive un nombre?

Una variable es un nombre ligado a un valor, pero dónde vale ese vínculo es el alcance. Las matemáticas también lo marcan: en f(x)=x2f(x) = x^2, la letra xx es un comodín que vive solo dentro de la definición. Fuera, xx puede significar algo completamente distinto. Python dibuja las mismas paredes alrededor de los cuerpos de las funciones: una variable creada dentro de una función es local, existe dentro de las paredes y en ningún otro sitio.

python
def my_func():
    x = 10
    print(x)  # funciona

my_func()
# print(x)  # NameError: x is not defined

Las variables definidas a nivel de módulo, en cambio, son visibles en todo lo que hay debajo, son globales:

python
counter = 0

def increment():
    global counter
    counter += 1

increment()
print(counter)  # 1

El problema de global es que deja que una función reescriba el mundo desde dentro. El vínculo cambia donde nada en la llamada te dijo que cambiaría. Prefiere devolver valores antes que alcanzar global, una función que devuelve es una función que puedes probar y razonar de forma aislada.

Alcance anidado y nonlocal

Las funciones pueden anidar, y una función interna puede leer una variable externa. Reescribirla, en cambio, exige la palabra clave nonlocal, una confesión de que el nombre pertenece al alcance envolvente:

python
def make_counter():
    count = 0
    def increment():
        nonlocal count
        count += 1
        return count
    return increment

counter = make_counter()
print(counter())  # 1
print(counter())  # 2

El increment interno lleva su propia memoria: cada llamada empuja el count capturado. Esto es una clausura, una función con un bolsillo de estado que arrastra consigo después de que su función envolvente haya terminado.

Lambda: la función en línea

Una función que cabe en una línea tiene taquigrafía. lambda crea una pequeña función anónima, una fórmula en forma de expresión:

python
add = lambda a, b: a + b
print(add(3, 5))  # 8

Es equivalente al def que ya conoces:

python
def add(a, b):
    return a + b

La diferencia es de peso: def escribe toda la ceremonia para cualquier cosa con pasos; lambda se queda en línea para una sola expresión, sin documento posterior, sin return, la expresión tras los dos puntos es el valor devuelto.

Lambdas con funciones de orden superior

Las lambdas ganan su sustento cuando se entregan a funciones que toman una función como entrada. Ordenar por puntuación, mapear cada elemento, quedarse con los que pasan una prueba, cada una es notación de construcción de conjuntos en código:

python
students = [("Alice", 85), ("Bob", 92), ("Charlie", 78)]

# Ordena por puntuación (segundo elemento)
by_score = sorted(students, key=lambda s: s[1])
print(by_score)  # [('Charlie', 78), ('Alice', 85), ('Bob', 92)]

# Map: aplicar una función a cada elemento — $\{2x \mid x \in \text{nums}\}$
nums = [1, 2, 3, 4]
doubled = list(map(lambda x: x * 2, nums))
# [2, 4, 6, 8]

# Filter: quedarse con los que pasan una prueba — $\{x \in \text{nums} \mid x \equiv 0 \pmod{2}\}$
evens = list(filter(lambda x: x % 2 == 0, nums))
# [2, 4]

map transforma cada elemento; filter conserva los que un predicado aprueba; sorted ordena por una clave elegida. Tres operaciones comunes sobre datos, cada una aceptando una función diminuta como su perilla de personalización.

Un ejemplo resuelto: la función limpia

El consejo del alcance, preferir return a global, tiene una forma lista: un precio con la tasa como parámetro:

python
def price_with_tax(price, rate=0.2):
    return round(price * (1 + rate), 2)

price_with_tax(10.0)        # 12.0
price_with_tax(10.0, 0.08)  # 10.8

La función limpia no necesita global: la tasa llega como parámetro, el mundo exterior queda intacto, y la fórmula se lee, precio(1+tasa)\text{precio} \cdot (1 + \text{tasa}). Todo ocurre dentro de las paredes, y el resultado vuelve por return.

Errores comunes

  • Usar global cuando bastaría un return. Oculta el efecto secundario y acopla la función a su entorno.
  • Abusar de las lambdas. Solo una expresión; en cuanto una lambda necesite dos pasos, hazla def.
  • Confundir el alcance en funciones anidadas. Cuando se lee una variable, Python sale hacia afuera buscándola; un grito nonlocal o global cambia quién puede escribirla. Lee esta lógica antes de suponer el vínculo.
  • sorted sin key ordena por el propio elemento. Las tuplas se ordenan léxicamente por su primer elemento primero; para ordenar por el segundo, la key es obligatoria, sorted(students, key=lambda s: s[1]).

🧩 Desafíos

🧩 Desafío, piensa primero, luego revela

Ordena las palabras words = ["banana", "pie", "Washington", "a"] por longitud.

💡 Respuesta: sorted(words, key=lambda w: len(w))['a', 'pie', 'banana', 'Washington'], la función clave eleva cada palabra al número que se compara.

🧩 Desafío, piensa primero, luego revela

Usa filter con una lambda para conservar las palabras de más de tres caracteres de ["hi", "hello", "hey", "howdy", "yo"].

💡 Respuesta: list(filter(lambda w: len(w) > 3, words))['hello', 'howdy'], el predicado es tu condición de pertenencia, y filter es el constructor de conjuntos.

🤔 Preguntas socráticas

  • ¿Por qué Python exige nonlocal en vez de dejar que las funciones internas reasignen libremente una variable externa? ¿Qué errores previene el requisito?
  • map/filter con lambda frente a una comprensión de listas, ¿cuándo es cada una la grafía más clara?
  • Una lambda admite solo una expresión. ¿Qué limitación se esconde tras esa regla?

✅ Comprobación rápida

1. ¿Qué devuelve sorted(["banana", "pie", "a"], key=len)?

2. ¿Qué palabra clave permite a una función interna modificar una variable externa?

alcancegloballambdasortedmapfilter