Bucles: while, for y control de iteraciones
Repetir trabajo sin copiar código: contadores, acumuladores y las herramientas para salir a tiempo
Un bucle repite un bloque de instrucciones mientras se cumpla una condición o hasta agotar una colección. Aquí aprendes a escribir while y for, a controlar range, a usar break, continue y pass, a acumular resultados y a evitar los dos fallos clásicos: el bucle infinito y el error de un elemento.
- Elegir entre while y for según el problema
- Recorrer secuencias y rangos con la firma correcta de range
- Controlar la iteración con break, continue y pass
- Acumular totales y contar elementos sin perder inicializaciones
- Detectar y corregir bucles infinitos y errores de un elemento
Antes necesitas: Condicionales: if, elif y else
En esta lección
- ¿Qué es un bucle?
- ¿Para qué sirven?
- ¿Cómo funciona por dentro?
- Sintaxis: `while`
- Sintaxis: `for` y `range`
- Control fino: `break`, `continue` y `pass`
- Ejemplo básico: total y promedio de ventas
- Ejemplo intermedio: bucles anidados
- Caso práctico: seguimiento de ventas mensuales
- Visualización: el acumulador paso a paso
- Errores comunes
- Buenas prácticas
- Ejercicios
- Soluciones explicadas
- Resumen
- Evaluación
Imagina que tienes que sumar las ventas de 40 000 filas de un archivo. Escribir 40 000 sumas es imposible; copiar y pegar la misma línea tampoco es programar. La solución es indicar el patrón una vez y pedirle a Python que lo repita: eso es un bucle.
Python ofrece dos herramientas. while repite mientras una condición siga siendo verdadera. for recorre los elementos de una colección y se detiene cuando no quedan. Saber cuál usar es la mitad del trabajo.
¿Qué es un bucle?
Un bucle es una estructura de control que ejecuta un bloque varias veces. Cada repetición se llama iteración. El bloque puede leer y modificar variables, y esas modificaciones son las que permiten que el bucle termine o que haga algo distinto en cada vuelta.
Piensa en lavar platos: repites «toma un plato, lávalo, déjalo en el escurridor» hasta que no queden platos. La condición de parada no es un número fijo, es un estado del mundo. Un while funciona exactamente así; un for se parece más a recorrer una lista de invitados y saludar a cada uno.
¿Para qué sirven?
Cualquier tarea repetitiva con un patrón es candidata a un bucle. En un proyecto real aparecen constantemente:
- Procesar datos: recorrer las filas de un CSV y sumar una columna.
- Calcular agregados: total, promedio, máximo o cuántas veces se cumple algo.
- Buscar: detenerte en cuanto encuentras el primer valor negativo.
- Generar secuencias: imprimir una tabla, contar del 1 al 10, avanzar de dos en dos.
- Machine Learning: repetir el entrenamiento durante
n_epocasy detenerlo si la pérdida deja de mejorar.
¿Cómo funciona por dentro?
En un while, Python evalúa la condición antes de cada vuelta. Si es verdadera, ejecuta el cuerpo y vuelve a la condición; si es falsa, sale y continúa con la línea siguiente. No hay un número máximo de vueltas: si la condición nunca se vuelve falsa, el programa se queda ahí.
En un for, Python pide elementos a un iterador hasta que se agota. No hay contador visible ni condición que escribir: la colección decide cuándo terminar. Cuando no quedan elementos, el iterador lanza internamente una señal de parada y el bucle acaba.
range no es una lista: es un objeto que genera números bajo demanda. Por eso range(1_000_000) no ocupa un millón de posiciones en memoria. Si necesitas verlo completo, conviértelo con list(...), pero para recorrerlo no hace falta.
Sintaxis: `while`
La forma es while condición: seguido de un bloque indentado. Antes del bucle debes inicializar las variables que la condición usa, y dentro debes actualizarlas; si no, la condición se queda congelada.
saldo = 100
retiro = 30
meses = 0
while saldo >= retiro:
saldo -= retiro
meses += 1
print(meses, saldo)- La condición
saldo >= retirose evalúa antes de cada vuelta. saldo -= retiroactualiza la variable que controla el final: sin esta línea el bucle sería infinito.meses += 1acumula cuántas veces se ejecutó el cuerpo.- Cuando el saldo queda en 10, la condición es falsa y el bucle sale.
- El resultado es
3 10: tres retiros y diez soles restantes.
Sintaxis: `for` y `range`
La forma es for variable in iterable: y el bloque indentado. En cada vuelta, variable toma el siguiente elemento. range genera enteros y tiene tres formas: range(fin), range(inicio, fin) y range(inicio, fin, paso). El límite fin nunca se incluye.
for i in range(1, 6):
print(i, i ** 2)
print(list(range(5, 0, -2)))La primera línea recorre 1, 2, 3, 4, 5: empieza en 1 y se detiene antes de 6. El cuerpo imprime cada número y su cuadrado, de 1 1 a 5 25. La última línea convierte a lista el rango 5, 3, 1, que usa paso negativo para contar hacia atrás. Si necesitaras incluir el 6, escribirías range(1, 7).
for i in range(1, 6):
print(i)#include <iostream>
int main() {
for (int i = 1; i <= 5; ++i) {
std::cout << i << std::endl;
}
return 0;
}En Python el final de `range` es exclusivo, por eso se escribe 6 para llegar a 5. En C++ el límite se escribe en la condición y suele ser inclusivo. Ese detalle provoca la mitad de los errores de un elemento cuando cambias de lenguaje.
Control fino: `break`, `continue` y `pass`
A veces no quieres esperar al final natural del bucle. break lo abandona por completo; continue salta al siguiente elemento sin ejecutar el resto del cuerpo; pass no hace nada y sirve como marcador cuando la sintaxis exige un bloque.
pedidos = [12, 0, 8, -1, 20]
validos = 0
for pedido in pedidos:
if pedido < 0:
break
if pedido == 0:
continue
validos += 1
print(validos)El 12 se cuenta, el 0 se salta con continue, el 8 se cuenta y el -1 corta todo con break. El 20 nunca se visita, así que validos termina en 2. Con continue en lugar de break, el -1 se saltaría y el 20 se contaría: el resultado sería 3.
Los bucles admiten un else que se ejecuta solo si el bucle terminó sin break. Es útil para búsquedas: si recorres una colección buscando algo y no lo encuentras, el else lo informa sin necesidad de una bandera extra.
objetivo = 7
for n in [2, 3, 4, 6]:
if n == objetivo:
print("encontrado")
break
else:
print("no encontrado")Ningún elemento es 7, el break no se ejecuta y por eso se imprime no encontrado. Si el objetivo fuera 4, se imprimiría encontrado y el else se saltaría. El else pertenece al for, no al if: su indentación está al mismo nivel que el for.
Ejemplo básico: total y promedio de ventas
El patrón del acumulador aparece en casi todos los análisis: una variable empieza en cero y crece dentro del bucle. Aquí se suma una lista de ventas y se calcula su promedio:
ventas = [120, 80, 150, 90]
total = 0
for venta in ventas:
total = total + venta
print(f"Total: {total}")
print(f"Promedio: {total / len(ventas)}")ventases la colección; elforla recorre de izquierda a derecha.total = 0es la inicialización: si la omites,total = total + ventafalla conNameErroren la primera vuelta.total = total + ventatambién se escribetotal += venta; suma el elemento actual al acumulado.- Al terminar,
totalvale 440 ylen(ventas)es 4. 440 / 4da110.0; la división con/producefloataunque el resultado sea exacto.
El bucle no imprime nada por sí mismo: solo construye el resultado. Imprimir dentro del bucle mostraría cuatro totales parciales, que a veces es útil para depurar pero no es lo que pide el problema. Separa el cálculo de la presentación.
Ejemplo intermedio: bucles anidados
Un bucle dentro de otro genera combinaciones: filas y columnas, alumnos y materias, productos y meses. El bucle interno se ejecuta completo por cada vuelta del externo.
for fila in range(1, 4):
linea = ""
for columna in range(1, 4):
linea += str(fila * columna) + " "
print(linea)El bucle externo da tres vueltas y el interno también: el cuerpo de la multiplicación se ejecuta 9 veces. En la primera fila, linea acumula 1 2 3 ; en la segunda, 2 4 6 ; en la tercera, 3 6 9 . linea se reinicia a cadena vacía en cada fila, y eso es lo que impide que las filas se mezclen.
Los anidados crecen rápido: dos bucles de 1 000 elementos producen un millón de iteraciones. Antes de anidar, pregúntate si basta un solo recorrido o una estructura auxiliar.
Caso práctico: seguimiento de ventas mensuales
Tienes las ventas de seis meses y una meta de 1 000. Necesitas el total, el promedio y cuántos meses superaron la meta. Un solo recorrido puede calcular las tres cosas a la vez:
ventas = [1250, 980, 1420, 1100, 870, 1600]
meta = 1000
sobre_meta = 0
total = 0
for venta in ventas:
total += venta
if venta >= meta:
sobre_meta += 1
promedio = total / len(ventas)
print(f"Total: {total}")
print(f"Promedio: {promedio:.2f}")
print(f"Meses sobre la meta: {sobre_meta}")La suma da 7220 y el promedio 1203.33, porque 7220 / 6 es 1203.333... y el formato corta a dos decimales. Alcanzaron la meta enero, marzo, abril y junio: cuatro meses. El condicional vive dentro del bucle, así que se evalúa seis veces, una por venta. Esta combinación de bucle y condicional es el esqueleto de casi cualquier informe.
Visualización: el acumulador paso a paso
La traza recorre una lista de dos ventas. Observa cómo total conserva su valor entre vueltas y cómo venta cambia en cada iteración.
ventas = [120, 80]total = 0for venta in ventas: total += ventaprint(total)—
Avanza paso a paso: observa la línea resaltada, las variables y la salida.
Errores comunes
| Mensaje o síntoma | Por qué ocurre | Cómo se arregla |
|---|---|---|
| El programa no termina nunca | La condición del while no cambia | Actualiza la variable dentro del bucle o añade un break |
NameError: name 'total' is not defined | Usaste total += x sin inicializar total | Escribe total = 0 antes del bucle |
TypeError: 'int' object is not iterable | Escribiste for i in 5: | Usa for i in range(5): |
IndentationError: expected an indented block | El cuerpo del bucle quedó al mismo nivel | Indenta con 4 espacios |
| Falta o sobra una iteración | Confundiste el final exclusivo de range | Para 1..5 usa range(1, 6) |
i = 1
while i <= 3:
print(i)i = 1
while i <= 3:
print(i)
i += 1En la versión incorrecta, `i` vale 1 para siempre y la condición nunca se vuelve falsa; la terminal se llena de unos hasta que interrumpes con `Ctrl+C`. La actualización debe estar dentro del bucle, no antes ni después.
Buenas prácticas
- Usa
forcuando conozcas la colección ywhilecuando la parada dependa de un estado. - Inicializa contadores y acumuladores justo antes del bucle, nunca dentro.
- Evita modificar la colección que estás recorriendo: itera sobre una copia si hace falta.
- Si el cuerpo supera las 15 líneas, extrae parte del trabajo a una función.
- Desconfía de los anidados con colecciones grandes: la cantidad de vueltas se multiplica.
- En un
while, escribe la actualización en las primeras líneas del cuerpo para no olvidarla.
Ejercicios
Suma de pares del 1 al 20
110. Resuélvelo con un for y un acumulador, sin escribir la lista a mano.Pista
range acepta un paso: empieza en 2 y avanza de 2 en 2. Recuerda que el límite superior es exclusivo.
Factorial con un bucle
1 * 2 * 3 * 4 * 5 * 6, usando un for y una variable que empiece en 1. Muestra el resultado, que debe ser 720.Pista
El acumulador de un producto se inicializa en 1, no en 0: cualquier cosa multiplicada por 0 da 0.
total = 0 for numero in (1, 6): total numero print(total)
Necesitas generar del 1 al 5 y sumar cada número al total.
Soluciones explicadas
En la suma de pares, el paso 2 evita el if y reduce las iteraciones a la mitad. El límite 21 parece raro hasta que recuerdas que range excluye el final. Comprueba siempre el primer y el último valor de cada rango.
En el factorial, la inicialización en 1 es la decisión crítica. El mismo patrón sirve para productos, potencias acumuladas y probabilidades conjuntas. Si el problema pidiera el factorial de 0, el bucle no se ejecutaría y el resultado sería correctamente 1: el caso base queda cubierto por la inicialización.
Resumen
- Un bucle repite un bloque; cada vuelta es una iteración.
whiledepende de una condición y exige inicializar y actualizar sus variables.forrecorre una colección y termina cuando el iterador se agota.range(inicio, fin, paso)excluye el final; el paso puede ser negativo.breaksale del bucle,continuesalta a la siguiente vuelta ypassno hace nada.- El
elsede un bucle se ejecuta solo si no hubobreak. - Los acumuladores se inicializan antes del bucle: 0 para sumas, 1 para productos.
- Los bucles anidados multiplican las iteraciones y deben usarse con cuidado.
Evaluación
¿Qué números produce range(2, 10, 3)?
¿Cuántas veces se ejecuta el cuerpo de for i in range(4):?
En for n in [1, 2, 3]: if n == 2: break, ¿qué ocurre?
¿Ya lo entendiste?
Márcala como completada para llevar tu progreso y desbloquear el siguiente paso de la ruta.