Funciones, scope y argumentos
Python · Lección 2
La idea
Una función en Python es un objeto como cualquier otro: se guarda en variables, se pasa como argumento, se devuelve desde otra función. Eso es lo que hace posible df.apply(mi_funcion) y todo el estilo funcional de pandas.
Y hay una regla de resolución de nombres — LEGB — que decide de dónde sale cada variable que una función menciona.
LEGB: dónde busca Python un nombre
Cuando dentro de una función escribes x, Python busca en este orden y se detiene en el primero que encuentre:
| Sigla | Ámbito | Qué es |
|---|---|---|
| L | Local | Dentro de la función actual |
| E | Enclosing | En la función que la contiene, si está anidada |
| G | Global | A nivel del módulo/archivo |
| B | Built-in | len, sum, print… |
Quita la línea x = "local" y vuelve a correr: interna ya no encuentra x localmente y sube al ámbito enclosing.
Asignar a un nombre dentro de una función lo vuelve local para toda la función, incluso antes de la línea de asignación.
Python ve la asignación, marca contador como local, y al intentar leerlo del lado derecho todavía no existe. La solución no es global — es devolver el valor y reasignarlo fuera. Las funciones que mutan estado global son la fuente número uno de bugs irreproducibles en notebooks.
Argumentos: los cuatro tipos
- Posicionales:
sucursal,mes— obligatorios, por orden. *extras: recoge los posicionales de más en una tupla.- Por defecto:
moneda="USD"— opcional. **opciones: recoge los nombrados de más en un diccionario.
La trampa del argumento mutable por defecto
Este es un clásico de entrevista, y algo que vas a ver en código real.
Por qué la lista se acumula entre llamadas
El def se ejecuta una sola vez, cuando Python lee el archivo — no en cada llamada. En ese momento evalúa las expresiones de los valores por defecto.
[] se evalúa entonces y produce un objeto lista. Ese objeto se guarda en el atributo __defaults__ de la función.
Cada llamada sin el argumento bolsa no crea una lista nueva: reutiliza ese mismo objeto guardado.
bolsa.append(item) es un método mutador sobre un objeto mutable (Lección 1): modifica el objeto compartido en su lugar. Por eso persiste entre llamadas.
Compruébalo:
El patrón correcto usa None como centinela:
Nota que aquí sí se usa is None y no == None — exactamente la regla de la Lección 1.
Funciones como objetos
lambda es solo una función anónima de una expresión. Úsala para funciones de una línea que se pasan como argumento; para cualquier otra cosa, def con nombre es más legible.
Ejercicio 1 — Arreglar el default mutable
Corrige la función para que cada llamada sin registro arranque con un diccionario vacío.
Usa None como valor por defecto y, en la primera línea del cuerpo, crea el diccionario si el argumento llegó como None. Recuerda comparar con is, no con ==.
Ejercicio 2 — Sin estado global
Reescribe esta función para que no dependa de una variable global: debe recibir el total actual y devolver el nuevo.
La función debe recibir dos parámetros (el acumulado y el nuevo valor) y devolver su suma. No debe asignar a ninguna variable de fuera.
Reto
En proyectos/notebooks/F0-retos.ipynb:
- Escribe un decorador
@cronometrarque imprima cuánto tardó la función que envuelve. Necesitarástime.perf_counteryfunctools.wraps. - Escribe
componer(f, g)que devuelva una función nueva equivalente af(g(x)). Verifica quecomponer(doblar, incrementar)(5)da 12. - Explica, en dos líneas, por qué
sorted(lista, key=lambda x: x[1])ordena por el segundo elemento. ¿Qué recibekeyy qué hacesortedcon lo que devuelve?
Para el Cerebro
Lee McKinney cap. 3 (secciones de funciones) con estas preguntas escritas antes:
- ¿Qué devuelve una función que no tiene
return? - ¿Puede una función devolver varios valores? ¿Qué está pasando realmente?
- ¿Qué es un closure y por qué una función anidada puede leer variables de la de afuera después de que esta terminó?
¿Qué significa LEGB?::Local, Enclosing, Global, Built-in — el orden en que Python resuelve un nombre
¿Cuándo se evalúan los valores por defecto de una función?::Una sola vez, al definir la función, no en cada llamada
¿Cuál es el patrón correcto para un default mutable?::Usar None como centinela y crear el objeto dentro del cuerpo
¿Qué recoge *args y qué recoge **kwargs?::*args los posicionales sobrantes en una tupla; **kwargs los nombrados en un dict
¿Por qué asignar a un nombre dentro de una función puede dar UnboundLocalError?::La asignación lo marca local para toda la función, incluso antes de esa línea
Fuentes
Lo que esta página demuestra sola. Los ejercicios corren en tu navegador.
Lo que viene de los libros.
- Python for Data Analysis 3E (McKinney — libro abierto), §3 Built-In Data Structures, Functions, and Files
Índices verificados el 11-09-2026 contra el índice publicado de cada libro.
→ Siguiente: Comprehensions e iteradores