Comprehensions e iteradores
Python · Lección 3
La idea
Una comprehension dice qué quieres, no cómo recorrerlo. Es el mismo salto mental que después harás en pandas cuando dejes de escribir bucles sobre filas y empieces a escribir operaciones sobre columnas — y en NumPy cuando vectorices.
La estructura siempre es la misma:
[ expresión for elemento in iterable if condición ]
qué devuelvo qué recorro qué filtro
El if es opcional. Se lee de izquierda a derecha, salvo la expresión del principio, que se aplica al final.
Las cuatro formas
Fíjate que el diccionario tiene tres claves, no cuatro: "costa" aparecía dos veces y la segunda sobrescribió a la primera.
Listas contra generadores: la diferencia es memoria
Por qué un generador no ocupa memoria
[x**2 for x in range(n)] construye la lista completa antes de devolverla: reserva memoria para los n resultados, todos a la vez.
(x**2 for x in range(n)) no calcula nada al crearse. Devuelve un objeto que recuerda dónde va en el recorrido.
Cada vez que pides el siguiente elemento — con next(), o implícitamente en un for — el generador calcula ese valor, lo entrega, y se congela hasta la próxima petición. Solo existe un valor a la vez.
Consecuencia: la memoria de un generador es O(1) sin importar n, y la de la lista es O(n). Pero el generador es de un solo uso: al terminar de recorrerlo queda agotado.
Cuándo usar cada uno: lista si vas a recorrerla más de una vez, indexarla o conocer su largo. Generador si solo vas a recorrerla una vez, sobre todo si es grande o infinita — leer un CSV de 10 GB línea por línea, por ejemplo.
Anidadas y el orden que confunde
El orden de los for es el mismo que en los bucles anidados equivalentes: el primero es el externo. Pero cuidado con esta otra forma, que es distinta:
Si necesitas dos niveles de anidamiento con condiciones, o la expresión no cabe cómoda en una línea, el bucle explícito se lee mejor. Una comprehension ilegible no es más “pythónica” — es peor código.
Herramientas que acompañan
any y all con un generador adentro se cortan apenas saben la respuesta: any para en el primer True. Con una lista tendrías que calcular todo primero.
Ejercicio 1 — Filtrar y transformar
De la lista de ventas, obtén una lista con el ticket promedio (venta ÷ transacciones) solo de las sucursales con más de 50 transacciones, redondeado a 2 decimales.
La expresión es round(d["venta"] / d["trx"], 2), el iterable es datos, y la condición filtra por d["trx"] > 50.
Ejercicio 2 — Dict comprehension
Construye un diccionario de sucursal a venta, solo para las que superan 2000.
Una dict comprehension va entre llaves y usa clave: valor como expresión: {d["sucursal"]: d["venta"] for d in datos if ...}.
Ejercicio 3 — Generador y cortocircuito
Usa any con un generador para saber si alguna sucursal tiene ticket promedio mayor a 35.
any(...) recibe un iterable de booleanos. Dentro de los paréntesis de any no hacen falta paréntesis extra para el generador: any(d["venta"] / d["trx"] > 35 for d in datos).
Reto
En proyectos/notebooks/F0-retos.ipynb:
- Escribe un generador
lineas_largas(ruta, n)que lea un archivo y entregue solo las líneas de más dencaracteres, sin cargar el archivo entero en memoria. Pruébalo con un archivo de ejemplo. - Toma una comprehension anidada de tres niveles y reescríbela como bucles explícitos. Decide cuál se lee mejor y anota por qué en
50-Erroreso en tu nota del tema. - Mide con
timeituna comprehension contra el bucle equivalente con.append()para 1 000 000 de elementos. Explica la diferencia: ¿de dónde sale?
Para el Cerebro
Lee McKinney cap. 3 (comprehensions y generadores) con estas preguntas escritas antes:
- ¿Qué hace
yieldy en qué se diferencia dereturn? - ¿Qué es
itertools.chainy cuándo lo usarías? - ¿Por qué
range(1_000_000)no ocupa memoria proporcional a un millón?
¿Cuál es la estructura de una comprehension?::[expresión for elemento in iterable if condición]
¿Cuánta memoria usa un generador frente a una lista de n elementos?::O(1) contra O(n)
¿Qué pasa al recorrer un generador dos veces?::La segunda pasada viene vacía: es de un solo uso
¿Por qué any() con generador es más rápido que con lista?::Cortocircuita en el primer True sin evaluar el resto
¿Cuándo NO usar una comprehension?::Cuando tiene anidamiento profundo o no cabe legible en una línea
¿Qué hace zip()?::Recorre dos o más iterables en paralelo, deteniéndose en el más corto
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: Archivos, errores y módulos