Bucles for y range: repetir un número de veces conocido
Cuando sabes cuántas veces hay que repetir algo, un bucle for es la opción adecuada. Las tres formas de range, por qué se excluye el final y cómo elegir entre for y while.
¿Cómo quieres aprender?
El problema que vamos a resolver
En el capítulo anterior, sumar del 1 al 5 costaba cuatro líneas, dos de las cuales solo servían para llevar la cuenta: un valor inicial y un incremento. Si olvidas el incremento, tienes un bucle infinito.
Pero fíjate en una cosa de ese tipo de trabajo: sabíamos de antemano cuántas veces se ejecutaría. Cinco. Cuando es así, no hay razón para llevar la cuenta tú: puedes dejárselo a Python.
Eso es exactamente lo que hace un bucle for. Y como el conteo no depende de ti, un bucle for sobre un range no puede volverse infinito por sí solo: el número de vueltas se fija cuando empieza el bucle. Esa es su mayor ventaja. (Hay una excepción: si recorres una lista y sigues añadiendo elementos a esa misma lista dentro del bucle, el bucle nunca termina. Las listas llegan en el próximo capítulo.)
Al terminar este capítulo podrás
- Ejecutar código un número conocido de veces con un bucle
for - Usar las tres formas de
range() - Explicar por qué
range(1, 5)produce cuatro números, y no cinco - Recorrer los caracteres de una cadena
- Decidir si una tarea necesita un bucle
foro un buclewhile
Requisitos previos: Bucles while: repetir mientras una condición se cumple.
La forma más sencilla
for number in range(5):
print(number)0
1
2
3
4Tres líneas de trabajo en una, sin ningún contador que gestionar. Léelo así: «para cada uno de los números que produce `range(5)`, ejecuta el bloque una vez; y cada vez, guarda ese número en `number`.»
Dos cosas llaman la atención enseguida:
Empieza en cero, y el 5 nunca aparece: son cinco números en total, del 0 al 4. Es la misma regla que Python aplica en todas partes: el índice final queda fuera en un slice, y así también ocurre en un range.
El nombre number lo eliges tú. for i in range(5) es igual de válido, e i es el nombre habitual para un contador. Pero cuando el número significa algo, ponle un nombre según ese significado: for student_number in range(30) se entiende por sí solo.
Las tres formas de range()
print("--- range(5) ---")
for i in range(5):
print(i, end=" ")
print()
print("--- range(2, 6) ---")
for i in range(2, 6):
print(i, end=" ")
print()
print("--- range(0, 10, 3) ---")
for i in range(0, 10, 3):
print(i, end=" ")
print()
print("--- range(5, 0, -1) ---")
for i in range(5, 0, -1):
print(i, end=" ")
print()--- range(5) ---
0 1 2 3 4
--- range(2, 6) ---
2 3 4 5
--- range(0, 10, 3) ---
0 3 6 9
--- range(5, 0, -1) ---
5 4 3 2 1Las reglas:
range(stop): empieza en0y termina antes destoprange(start, stop): empieza enstarty termina antes destoprange(start, stop, step): avanzastepen cada vuelta; unstepnegativo cuenta hacia atrás
Revisa las dos últimas. range(0, 10, 3) da 0 3 6 9: el siguiente sería 12, que se pasa de 10, así que se detiene. Y range(5, 0, -1) da 5 4 3 2 1: el 0 nunca aparece, porque aquí el final también queda excluido.
¿Por qué se excluye el final? Porque hace más fácil la aritmética. ¿Cuántos números hay enrange(0, 5)?5 - 0, es decir, cinco. ¿Y enrange(3, 8)?8 - 3, también cinco. Restas y obtienes la cantidad, sin preguntarte si hay que sumar uno. Y dos rangos colocados uno detrás de otro (range(0, 5)yrange(5, 10)) no dejan ningún número fuera ni repiten ninguno.
Cuando quieres ir del uno al diez
Este error aparece tan a menudo que merece su propia sección:
print("Wrong — stops at 9:")
for i in range(1, 10):
print(i, end=" ")
print()
print("Right — includes 10:")
for i in range(1, 11):
print(i, end=" ")
print()Wrong — stops at 9:
1 2 3 4 5 6 7 8 9
Right — includes 10:
1 2 3 4 5 6 7 8 9 10La regla en una línea: escribe uno más que el último número que quieres como stop.
Acumular — ahora, la forma fácil
total = 0
for number in range(1, 6):
total = total + number
print("Sum of 1 to 5:", total)Sum of 1 to 5: 15Compáralo con la versión while del mismo trabajo: no hay que crear un contador, ni incrementarlo, ni existe riesgo de bucle infinito. Solo el acumulador sigue teniendo que empezar fuera del bucle, igual que antes.
Recorrer una cadena
for no solo recorre números: también recorre una cadena, carácter a carácter:
word = "Python"
for letter in word:
print(letter, end="-")
print()
vowel_count = 0
for letter in "programming":
if letter in "aeiou":
vowel_count = vowel_count + 1
print("Vowels:", vowel_count)P-y-t-h-o-n-
Vowels: 3Aquí no hace falta range, porque no es necesario: for letter in word recorre los caracteres directamente. Es más sencillo que hacer cálculos con índices, y no hay ningún IndexError que temer.
Cuando necesitas a la vez el índice y el carácter, existe enumerate(); lo veremos en el capítulo de listas.
break y continue también funcionan aquí
Exactamente igual que en un while:
for number in range(1, 20):
if number % 7 == 0:
print("First multiple of 7:", number)
breakFirst multiple of 7: 7Elegir entre for y while
Hazte una sola pregunta: ¿se conoce el número de repeticiones antes de que empiece el bucle?
Si la respuesta es sí, usa for:
- Ejecutar cinco veces
- Ir del 1 al 100
- Mirar cada carácter de una palabra
- Hacer algo con cada elemento de una lista
Si no, usa while:
- Seguir preguntando hasta que la entrada sea válida
- Ejecutar hasta que la persona escriba
quit - Leer mientras queden líneas en un archivo
En caso de duda, elige for. La razón es sencilla: un bucle for sobre un range o sobre una cadena fija siempre termina, y un bucle while no. Cuando los dos sirven, la mejor opción es la que permite cometer menos errores.
Un ejemplo completo
multiplication.py:
# Print a multiplication table, then a small summary
number = int(input("Which table? "))
upto = int(input("Up to? "))
print()
print(f"--- Table of {number} ---")
total = 0
for i in range(1, upto + 1):
result = number * i
total = total + result
print(f"{number} x {i:2} = {result:4}")
print()
print(f"Rows : {upto}")
print(f"Sum : {total}")
print(f"Average : {total / upto:.2f}")Which table? 7
Up to? 5
--- Table of 7 ---
7 x 1 = 7
7 x 2 = 14
7 x 3 = 21
7 x 4 = 28
7 x 5 = 35
Rows : 5
Sum : 105
Average : 21.00Tres cosas que observar. Primero, range(1, upto + 1): para llegar a upto hizo falta escribir uno más. Segundo, {i:2} y {result:4}: dentro de una f-string puedes indicar el ancho que debe ocupar un número, lo que mantiene las columnas alineadas. Tercero, total empieza fuera del bucle y crece dentro: es el mismo acumulador de antes.
Y hazte una pregunta: ¿qué pasa si la persona responde 0 a Up to?? range(1, 1) no produce ningún número, así que el bucle nunca se ejecuta, y entonces total / upto divide entre cero. Es la misma lección del capítulo anterior: antes de usar lo que acumuló un bucle, comprueba que haya acumulado algo.
Cuando algo falla
Falta el último número range(1, 10) termina en 9. Suma uno al stop: range(1, 11).
TypeError: 'float' object cannot be interpreted as an integer range() solo acepta números enteros (int). range(2.5) o range(1, n / 2) no funcionarán: convierte con int() o divide con //.
SyntaxError: expected ':' Falta el dos puntos al final de la línea del for.
IndentationError: expected an indented block after 'for' statement La línea dentro del bucle no tiene sangría.
El bucle nunca se ejecutó El range está vacío. range(5, 0) no produce nada: para contar hacia atrás necesitas el tercer argumento: range(5, 0, -1).
El total es 0 después del bucle La línea total = 0 se ha colado dentro del bucle, así que se reinicia en cada vuelta. Tiene que estar fuera.
Necesitas fuera del bucle una variable creada dentro, pero da NameError El range estaba vacío, así que el bucle nunca se ejecutó y la variable nunca llegó a crearse. Dale un valor inicial antes del bucle.
Paso 4 de 6 — Predice
Comprueba lo que has entendido
¿Qué imprime este bucle?
for i in range(1, 5):
print(i, end=" ")- A1 2 3 4 5
- B1 2 3
- C0 1 2 3 4
- D1 2 3 4
El tercer argumento fija el paso. ¿Cuál es la salida?
for i in range(0, 10, 3):
print(i, end=" ")- A3 6 9
- B0 3 6 9
- C0 1 2 3 4 5 6 7 8 9
- D0 3 6 9 12
La intención era sumar del 1 al 10, que da 55. Pero imprime 45. ¿Por qué?
total = 0
for number in range(1, 10):
total = total + number
print("Sum of 1 to 10:", total)- A`total` se inicializa fuera del bucle, cuando debería hacerlo dentro
- BUsar un `while` en lugar de `for` daría el resultado correcto
- CDebería ser `total + i` en vez de `total + number`
- D`range(1, 10)` termina en `9` y deja fuera el `10`: hace falta `range(1, 11)`
Para responder necesitas una cuenta
Inicia sesión para comprobar tus respuestas
Las preguntas están arriba, y resolverlas mentalmente es lo que de verdad importa. Inicia sesión para ver las respuestas, las explicaciones y las pistas de tres niveles.
Tu turno
Escribe un archivo llamado stars.py que pida un número e imprima un triángulo. Con 5:
*
**
***
****
*****Después añade estas tres cosas:
- Imprime al final el número total de estrellas (15 para una entrada de 5)
- Imprime también el triángulo boca abajo: cinco arriba y una abajo
- Imprime una versión que salte las filas de número par (usa
continue)
Hay una forma fácil de comprobar el primero: calcula a mano la suma del 1 al 5 y mira si tu programa coincide. Y ¿recuerdas "*" * i? Para construir una fila de estrellas no hace falta un bucle dentro del bucle.
Paso 6 de 6
Reto — el quiz del capítulo
Diez preguntas de fácil a difícil. Las últimas son difíciles a propósito.
Inicia sesión para hacer el quiz