60  Ciclos for y while en Python

Fecha: 17 de noviembre, 2026

Un ciclo (o bucle) permite repetir un bloque de instrucciones sin tener que escribirlas muchas veces. Python tiene dos tipos de ciclos: for repite el bloque una vez por cada elemento de una colección, y while lo repite mientras una condición sea verdadera.

Ya usamos ciclos en Bash (capítulo de Bucles (for loops)); la idea es la misma, solo cambia la sintaxis. En este capítulo veremos:

60.1 Estructura de un ciclo for

for elemento in coleccion:
    instruccion_1     # Se repiten una vez por cada elemento
    instruccion_2

instruccion_3         # Se ejecuta una sola vez, al terminar el ciclo

Igual que en los condicionales:

  1. La línea del for termina con dos puntos (:).
  2. Las instrucciones que se repiten llevan indentación de 4 espacios.
  3. No hay palabra de cierre (en Bash usábamos done): el bloque termina cuando termina la indentación.

En cada iteración (cada vuelta del ciclo), la variable elemento hace referencia al siguiente objeto de la colección:

Código
frutas = ["manzana", "pera", "uva"]

for fruta in frutas:
    print("Me gusta la", fruta)
Me gusta la manzana
Me gusta la pera
Me gusta la uva
Código
print("Fin del ciclo")
Fin del ciclo
Iteración Valor de fruta Se muestra
1 "manzana" Me gusta la manzana
2 "pera" Me gusta la pera
3 "uva" Me gusta la uva
Tip

Elige un nombre de variable que describa un elemento de la colección: for fruta in frutas, for numero in numeros, for estudiante in estudiantes. Así el código se lee casi como en español.

60.2 Recorrer distintos tipos de objetos

for funciona con cualquier objeto iterable, es decir, cualquier colección cuyos elementos se puedan recorrer uno por uno:

Objeto Cada iteración entrega… Ejemplo
list Cada elemento, en orden. for x in [3, 1, 2]:
tuple Cada elemento, en orden. for x in (3, 1, 2):
str Cada carácter. for letra in "hola":
set Cada elemento, sin orden garantizado. for x in {3, 1, 2}:
dict Cada clave. for clave in diccionario:
range Cada número de la secuencia. for i in range(5):

Recorrer una cadena:

Código
for letra in "Python":
    print(letra)
P
y
t
h
o
n

Recorrer un diccionario: usa el método items() para obtener la clave y el valor al mismo tiempo.

Código
estudiante = {"nombre": "Ana", "edad": 19, "semestre": 1}

for clave, valor in estudiante.items():
    print(clave, "->", valor)
nombre -> Ana
edad -> 19
semestre -> 1

En for clave, valor in ..., cada elemento de items() es una tupla de dos valores, ("nombre", "Ana"), que Python desempaqueta en dos variables.

60.3 La función range()

range() genera una secuencia de números enteros. Es la forma más común de repetir algo un número determinado de veces.

Forma Genera Ejemplo Resultado
range(fin) De 0 a fin - 1. range(5) 0, 1, 2, 3, 4
range(inicio, fin) De inicio a fin - 1. range(1, 6) 1, 2, 3, 4, 5
range(inicio, fin, paso) De inicio a fin - 1, de paso en paso. range(0, 11, 2) 0, 2, 4, 6, 8, 10
Paso negativo Cuenta hacia atrás. range(10, 0, -2) 10, 8, 6, 4, 2
Importante

El valor fin nunca se incluye, igual que en los rangos de índices (lista[1:4]). Para obtener los números del 1 al 10 escribe range(1, 11).

Código
for i in range(1, 6):
    print(i, "al cuadrado es", i ** 2)
1 al cuadrado es 1
2 al cuadrado es 4
3 al cuadrado es 9
4 al cuadrado es 16
5 al cuadrado es 25

Para ver todos los números de un range de una vez, conviértelo en lista:

Código
print(list(range(10, 0, -2)))
[10, 8, 6, 4, 2]

60.3.1 Diferencias con Bash

Bash Python
Inicio for i in 1 2 3; do for i in [1, 2, 3]:
Rango del 1 al 5 for i in {1..5}; do o $(seq 1 5) for i in range(1, 6):
Rango con paso {0..10..2} o $(seq 0 2 10) range(0, 11, 2)
Usar la variable echo $i print(i)
Cierre done No hay: termina la indentación.

60.4 Acumuladores y contadores

Un acumulador es una variable que va guardando un resultado parcial en cada iteración. Siempre sigue tres pasos:

  1. Inicializar la variable antes del ciclo.
  2. Actualizarla dentro del ciclo.
  3. Usarla después del ciclo.

Suma (se inicializa en 0, el neutro de la suma): \(\sum_{i=1}^{5} i\)

Código
suma = 0                      # 1. Inicializar

for i in range(1, 6):
    suma = suma + i           # 2. Actualizar
    print("i =", i, " suma parcial =", suma)
i = 1  suma parcial = 1
i = 2  suma parcial = 3
i = 3  suma parcial = 6
i = 4  suma parcial = 10
i = 5  suma parcial = 15
Código
print("Suma total:", suma)    # 3. Usar
Suma total: 15

Producto (se inicializa en 1, el neutro de la multiplicación): \(5! = 1 \cdot 2 \cdot 3 \cdot 4 \cdot 5\)

Código
factorial = 1

for i in range(1, 6):
    factorial = factorial * i

print("5! =", factorial)
5! = 120

Construir una lista (se inicializa con la lista vacía []):

Código
cuadrados = []

for i in range(1, 6):
    cuadrados.append(i ** 2)

print(cuadrados)
[1, 4, 9, 16, 25]

60.4.1 Operadores de asignación abreviados

Como actualizar una variable es muy común, Python tiene una forma abreviada:

Forma larga Forma abreviada
suma = suma + i suma += i
resta = resta - i resta -= i
producto = producto * i producto *= i
cociente = cociente / i cociente /= i
contador = contador + 1 contador += 1

60.5 for con condicionales

Dentro de un ciclo podemos usar if para actuar solo sobre algunos elementos. Por ejemplo, un contador de números pares y una lista con los impares:

Código
numeros = [4, 7, 10, 13, 16, 19]

pares = 0
impares = []

for numero in numeros:
    if numero % 2 == 0:
        pares += 1
    else:
        impares.append(numero)

print("Cantidad de pares:", pares)
Cantidad de pares: 3
Código
print("Impares:", impares)
Impares: [7, 13, 19]

Observa los dos niveles de indentación: 4 espacios para lo que está dentro del for y 8 para lo que está dentro del if.

60.5.1 break: salir del ciclo

break termina el ciclo inmediatamente, aunque falten elementos por recorrer. Es útil cuando ya encontramos lo que buscábamos:

Código
numeros = [3, 8, 12, 5, 20, 7]

for numero in numeros:
    if numero > 10:
        print("El primer número mayor que 10 es", numero)
        break
    print("Revisando", numero)
Revisando 3
Revisando 8
El primer número mayor que 10 es 12

60.5.2 continue: saltar a la siguiente iteración

continue salta el resto del bloque y pasa al siguiente elemento:

Código
for i in range(1, 11):
    if i % 3 == 0:
        continue           # Salta los múltiplos de 3
    print(i, end=" ")
1 2 4 5 7 8 10 

El argumento end=" " de print() muestra los valores en la misma línea, separados por un espacio.

60.6 Ciclos while

El ciclo while repite un bloque mientras una condición sea verdadera. A diferencia de for, no recorre una colección: revisa la condición antes de cada vuelta y se detiene en cuanto la condición es falsa.

while condicion:
    instruccion_1     # Se repiten mientras la condición sea True
    instruccion_2

instruccion_3         # Se ejecuta al terminar el ciclo
Código
contador = 1

while contador <= 5:
    print("Número:", contador)
    contador += 1        # ¡Importante! Actualizar la variable de la condición
Número: 1
Número: 2
Número: 3
Número: 4
Número: 5
Código
print("Fin del ciclo")
Fin del ciclo

En cada vuelta ocurre lo siguiente:

  1. Python evalúa la condición contador <= 5.
  2. Si es True, ejecuta el bloque: muestra el número y aumenta contador en 1.
  3. Regresa al paso 1. Cuando contador vale 6, la condición es False y el ciclo termina.

60.6.1 ¿Cuándo usar for y cuándo while?

for while
Repite… Una vez por cada elemento de una colección. Mientras una condición sea verdadera.
¿Sabemos cuántas vueltas dará? Sí: tantas como elementos. No necesariamente.
Ejemplo típico Recorrer una lista, sumar del 1 al 100. Repetir hasta alcanzar una precisión, pedir un dato hasta que sea válido.
Riesgo Muy bajo. Ciclo infinito si la condición nunca se vuelve falsa.

Un problema donde no sabemos cuántas vueltas necesitamos: ¿cuántos términos de la serie de Leibniz hacen falta para que la aproximación de \(\pi\) tenga un error menor que 0.01?

Código
import math

suma = 0
k = 0

while abs(4 * suma - math.pi) >= 0.01:
    suma += (-1) ** k / (2 * k + 1)
    k += 1

print("Términos necesarios:", k)
Términos necesarios: 100
Código
print("Aproximación:", 4 * suma)
Aproximación: 3.1315929035585537

60.6.2 Diferencias con Bash

Bash Python
Inicio while [ "$contador" -le 5 ]; do while contador <= 5:
Incrementar contador=$((contador + 1)) contador += 1
Cierre done No hay: termina la indentación.

60.6.3 ¡Cuidado con los ciclos infinitos!

Si la condición nunca se vuelve falsa, el ciclo no termina. El error más común es olvidar actualizar la variable de la condición:

contador = 1
while contador <= 5:
    print(contador)      # contador siempre vale 1: ¡ciclo infinito!
Advertencia

Si un programa se queda “atorado” en un ciclo infinito, detenlo: en la consola o la Terminal presiona Ctrl + C; en Jupyter o Colab usa el botón ■ (Interrumpir). En los editores de esta página, recarga la página.

60.6.4 while True con break

A veces la condición para salir se conoce dentro del ciclo. Entonces se usa while True (que siempre es verdadero) junto con break:

Código
n = 27
pasos = 0

while True:
    if n == 1:
        break            # Salir del ciclo
    if n % 2 == 0:
        n = n // 2
    else:
        n = 3 * n + 1
    pasos += 1

print("Pasos para llegar a 1:", pasos)
Pasos para llegar a 1: 111

break y continue funcionan igual en while que en for.

60.7 Ciclos anidados

Un ciclo puede ir dentro de otro. El ciclo interno se ejecuta completo en cada iteración del ciclo externo:

Código
for i in range(1, 4):
    for j in range(1, 4):
        print(i, "x", j, "=", i * j)
    print("---")
1 x 1 = 1
1 x 2 = 2
1 x 3 = 3
---
2 x 1 = 2
2 x 2 = 4
2 x 3 = 6
---
3 x 1 = 3
3 x 2 = 6
3 x 3 = 9
---

Si el ciclo externo da 3 vueltas y el interno 3, el bloque interno se ejecuta \(3 \times 3 = 9\) veces.

60.8 Funciones útiles: enumerate() y zip()

enumerate() entrega la posición y el elemento al mismo tiempo:

Código
estudiantes = ["Ana", "Luis", "Sofía"]

for posicion, nombre in enumerate(estudiantes, start=1):
    print(posicion, nombre)
1 Ana
2 Luis
3 Sofía

zip() recorre varias listas en paralelo:

Código
nombres = ["Ana", "Luis", "Sofía"]
calificaciones = [9.5, 8, 10]

for nombre, calificacion in zip(nombres, calificaciones):
    print(nombre, "obtuvo", calificacion)
Ana obtuvo 9.5
Luis obtuvo 8
Sofía obtuvo 10

60.9 Comprensiones de listas

Una comprensión de listas es una forma corta de construir una lista con un ciclo for, en una sola línea:

nueva_lista = [expresion for elemento in coleccion if condicion]

Las dos versiones siguientes producen la misma lista:

Código
# Con un ciclo for
pares_cuadrados = []
for i in range(1, 11):
    if i % 2 == 0:
        pares_cuadrados.append(i ** 2)
print(pares_cuadrados)
[4, 16, 36, 64, 100]
Código
# Con una comprensión de listas
pares_cuadrados = [i ** 2 for i in range(1, 11) if i % 2 == 0]
print(pares_cuadrados)
[4, 16, 36, 64, 100]

Se parece mucho a la notación de conjuntos en matemáticas: \(\{\, i^2 \mid i \in \{1, \dots, 10\},\ i \text{ par} \,\}\).

Tip

Esta es la sintaxis que usamos en la 🐍 Actividad 2 (atributos y métodos) para ocultar los nombres que empiezan con _: [nombre for nombre in dir(numero) if not nombre.startswith("_")].

60.10 Ciclos for vs. NumPy

En el capítulo de NumPy vimos que podemos operar sobre todo el arreglo a la vez (vectorización). Muchos problemas que resolvemos con un ciclo for se pueden resolver así:

Problema Con un ciclo for Con NumPy
Suma de 1 a 100 for i in range(1, 101): suma += i np.arange(1, 101).sum()
Factorial de 10 for i in range(1, 11): factorial *= i np.arange(1, 11).prod()
Cuadrados del 1 al 5 for i in range(1, 6): cuadrados.append(i ** 2) np.arange(1, 6) ** 2
Múltiplos de 3 hasta 30 for + if + append() a = np.arange(1, 31) y a[a % 3 == 0]

Además de ser más corto, el código vectorizado es mucho más rápido, porque NumPy hace los cálculos internamente en el lenguaje C. Compruébalo con la suma de los cuadrados de los primeros 1 000 000 de números:

60.11 Errores comunes

Error Ejemplo Corrección
Olvidar los dos puntos for i in range(5) (SyntaxError) for i in range(5):
Olvidar la indentación print(i) alineado con el for (IndentationError) Indenta 4 espacios.
Inicializar el acumulador dentro del ciclo for i in ...: y después suma = 0 Inicializa antes del for.
Olvidar que range() no incluye el final range(1, 10) para “del 1 al 10” range(1, 11)
Recorrer un número for i in 5: (TypeError) for i in range(5):
Usar índices sin necesidad for i in range(len(lista)): print(lista[i]) for elemento in lista: print(elemento)
Modificar una lista mientras se recorre for x in lista: lista.remove(x) Construye una lista nueva.
Olvidar actualizar la variable de un while while i < 5: print(i) (ciclo infinito) Agrega i += 1 dentro del ciclo.

60.12 Ejercicios

Resuelve los ejercicios en los editores interactivos. Recuerda que lo que escribas no se guarda al recargar la página.

60.12.1 Ejercicio 1. La suma de Gauss

Se cuenta que, de niño, Carl Friedrich Gauss sumó los números del 1 al 100 en unos segundos. Calcula \(\sum_{i=1}^{100} i\) con un ciclo for y un acumulador. Después compara tu resultado con la fórmula de Gauss: \(\frac{n(n+1)}{2}\).

NotaPista

La suma se inicializa en 0. Para incluir el 100, el rango debe ser range(1, n + 1).

TipSolución
n = 100
suma = 0

for i in range(1, n + 1):
    suma += i

print("Con el ciclo:", suma)
print("Con la fórmula:", n * (n + 1) // 2)
suma   # 5050

60.12.2 Ejercicio 2. Factorial

Calcula \(10! = 1 \cdot 2 \cdot 3 \cdots 10\) con un ciclo for.

NotaPista

El neutro de la multiplicación es 1. Usa factorial *= i y range(1, n + 1).

TipSolución
n = 10
factorial = 1

for i in range(1, n + 1):
    factorial *= i

print(n, "! =", factorial)
factorial   # 3628800

60.12.3 Ejercicio 3. Múltiplos de 3

Construye la lista multiplos con todos los múltiplos de 3 entre 1 y 30 (incluido), usando un ciclo for y un if. Después intenta obtener la misma lista con range() usando un paso de 3, sin if.

NotaPista

Un número es múltiplo de 3 si numero % 3 == 0. Para agregarlo a la lista usa multiplos.append(numero).

TipSolución
multiplos = []

for numero in range(1, 31):
    if numero % 3 == 0:
        multiplos.append(numero)

print(multiplos)
print(list(range(3, 31, 3)))   # Misma lista, sin if
multiplos

60.12.4 Ejercicio 4. ¿Es un número primo?

Un número \(n > 1\) es primo si sus únicos divisores son 1 y él mismo. Completa el programa para revisar todos los posibles divisores entre 2 y \(n - 1\): si encuentras uno, el número no es primo y puedes salir del ciclo con break.

Prueba con 97, 91, 2 y 1.

NotaPista

divisor divide a n si n % divisor == 0. Escribe break después del print(), con la misma indentación.

TipSolución
n = 97

es_primo = n > 1

for divisor in range(2, n):
    if n % divisor == 0:
        es_primo = False
        print(n, "es divisible entre", divisor)
        break

print(n, "es primo:", es_primo)
es_primo   # True

Para números grandes basta con revisar los divisores hasta \(\sqrt{n}\): range(2, int(n ** 0.5) + 1). ¿Por qué?

60.12.5 Ejercicio 5. Sucesión de Fibonacci

La sucesión de Fibonacci empieza con 0 y 1, y cada término es la suma de los dos anteriores: \(F_n = F_{n-1} + F_{n-2}\).

Completa la lista fibonacci para que tenga los primeros 10 términos.

NotaPista

La lista ya tiene 2 términos, así que el ciclo debe dar 8 vueltas: range(8). Los dos últimos elementos de la lista son fibonacci[-1] y fibonacci[-2].

TipSolución
fibonacci = [0, 1]

for i in range(8):
    siguiente = fibonacci[-1] + fibonacci[-2]
    fibonacci.append(siguiente)

print(fibonacci)
fibonacci   # [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]

Observa que la variable i no se usa dentro del ciclo: solo sirve para repetir 8 veces. En estos casos es común llamarla _: for _ in range(8):.

60.12.6 Ejercicio 6. Aproximar \(\pi\)

La serie de Leibniz permite aproximar \(\pi\):

\[\pi = 4 \sum_{k=0}^{\infty} \frac{(-1)^k}{2k + 1} = 4 \left(1 - \frac{1}{3} + \frac{1}{5} - \frac{1}{7} + \cdots\right)\]

Calcula la aproximación con los primeros 1000 términos (\(k = 0, 1, \dots, 999\)) y compárala con el valor real.

NotaPista

Recorre range(terminos) y en cada iteración suma (-1) ** k / (2 * k + 1). El signo alterna porque \((-1)^k\) vale \(1\) si \(k\) es par y \(-1\) si es impar.

TipSolución
terminos = 1000
suma = 0

for k in range(terminos):
    suma += (-1) ** k / (2 * k + 1)

aproximacion = 4 * suma
print("Aproximación:", aproximacion)   # 3.1405926538397932
print("Valor real:  ", 3.141592653589793)
aproximacion

60.12.7 Ejercicio 7. Aproximar \(\pi\) sin ciclos

En el ejercicio anterior aproximamos \(\pi\) con un ciclo for:

\[\pi \approx 4 \sum_{k=0}^{999} \frac{(-1)^k}{2k + 1}\]

Calcula la misma aproximación con NumPy, sin usar for: crea un arreglo k con los valores de 0 a 999, calcula todos los términos a la vez y súmalos.

NotaPista

k = np.arange(1000). La expresión (-1) ** k / (2 * k + 1) se calcula para todos los valores de k a la vez. Después usa np.sum() o .sum().

TipSolución
import numpy as np

k = np.arange(1000)
terminos = (-1.0) ** k / (2 * k + 1)
aproximacion = 4 * terminos.sum()

print("Aproximación:", aproximacion)   # 3.1405926538397932
print("Valor real:  ", np.pi)
aproximacion

Usamos -1.0 en lugar de -1 para que NumPy trabaje con decimales desde el inicio.

60.12.8 Ejercicio 8. La conjetura de Collatz

Toma un número entero positivo \(n\). Si es par, divídelo entre 2; si es impar, multiplícalo por 3 y súmale 1. Repite el proceso. La conjetura de Collatz dice que, sin importar con qué número empieces, siempre llegarás a 1 (¡nadie lo ha demostrado todavía!).

Con un ciclo while, cuenta cuántos pasos se necesitan para llegar a 1 empezando en \(n = 6\) y guarda la sucesión en la lista sucesion. Deja pasos en la última línea. Después prueba con \(n = 27\).

NotaPista

El ciclo debe repetirse mientras n != 1. Un número es par si n % 2 == 0. Si es impar, el nuevo valor es 3 * n + 1.

TipSolución
n = 6
pasos = 0
sucesion = [n]

while n != 1:
    if n % 2 == 0:
        n = n // 2
    else:
        n = 3 * n + 1
    sucesion.append(n)
    pasos += 1

print(sucesion)   # [6, 3, 10, 5, 16, 8, 4, 2, 1]
pasos             # 8

Usamos while porque no sabemos de antemano cuántos pasos se necesitan.

60.12.9 Ejercicio 9. Raíz cuadrada con el método de Newton

El método de Newton aproxima \(\sqrt{2}\) con la fórmula \(x_{\text{nuevo}} = x - \dfrac{x^2 - 2}{2x}\), empezando en \(x = 1\). Cada vuelta mejora la aproximación.

Repite la fórmula mientras el error \(|x^2 - 2|\) sea mayor que tolerancia. Cuenta las iteraciones y deja x en la última línea.

NotaPista

La condición es abs(x ** 2 - 2) > tolerancia y la actualización x = x - (x ** 2 - 2) / (2 * x).

TipSolución
x = 1.0
tolerancia = 1e-12
iteraciones = 0

while abs(x ** 2 - 2) > tolerancia:
    x = x - (x ** 2 - 2) / (2 * x)
    iteraciones += 1
    print("Iteración", iteraciones, ": x =", x)

print("Valor real:", 2 ** 0.5)
x   # 1.4142135623730951

60.13 Reto final: el contador de palabras

Escribe un programa que, a partir de la cadena texto:

  1. Convierta todo a minúsculas y separe las palabras.
  2. Guarde en un conjunto las palabras únicas.
  3. Con un ciclo for, guarde en un diccionario cuántas veces aparece cada palabra única.
  4. Deje en la última línea la palabra que más se repite.
NotaPista

Puedes encadenar métodos: texto.lower().split(). Para el conjunto usa set(palabras) y para contar palabras.count(palabra). En la última línea, max(conteo, key=conteo.get) busca la clave con el valor más grande.

TipSolución
texto = "Python es divertido y Python es poderoso y R también es poderoso"

palabras = texto.lower().split()
unicas = set(palabras)

conteo = {}
for palabra in unicas:
    conteo[palabra] = palabras.count(palabra)

print(conteo)
max(conteo, key=conteo.get)   # 'es'

60.14 Resumen

Tema Idea clave
for elemento in coleccion: Repite el bloque una vez por cada elemento. Termina con : y usa 4 espacios de indentación.
Iterables list, tuple, str, set, dict (claves) y range.
range(inicio, fin, paso) Genera enteros; el fin no se incluye.
Acumuladores Inicializar antes del ciclo (0 para sumar, 1 para multiplicar, [] para listas), actualizar dentro, usar después.
+=, *= Formas abreviadas de actualizar una variable.
while condicion: Repite mientras la condición sea verdadera; cuidado con los ciclos infinitos.
break / continue Salir del ciclo / saltar a la siguiente iteración (en for y while).
enumerate() / zip() Posición y elemento / varias listas en paralelo.
Comprensión de listas [expresion for x in coleccion if condicion]

60.15 Referencias