Range, Enumerate y Zip
Genera secuencias de números, rastrea índices y combina iterables.
- Usar range() para generar secuencias de números
- Usar enumerate() para obtener índice + valor durante la iteración
- Usar zip() para iterar sobre varias secuencias en paralelo
- Escribir bucles pitónicos que eviten el rastreo manual de índices
Tres herramientas que superan al conteo manual
Los bucles te dieron la repetición; esta lección te entrega los tres ayudantes que te quitan el conteo de las manos. Cada uno reemplaza un hábito que te enseñaron a escribir a mano, y cada uno es la respuesta a una irritación recurrente: generar números, necesitar la posición de un elemento y emparejar dos listas. Juntos son la diferencia entre un bucle que teclea y un bucle que se lee.
Range: la secuencia aritmética, perezosa
En la lección anterior sumaste con range(5). Merece una mirada de cerca, es la herramienta clásica para “hacer esto un número conocido de veces”:
for i in range(5):
print(i) # 0 1 2 3 4range tiene tres formas, espejo de la progresión aritmética :
range(5) # 0, 1, 2, 3, 4
range(2, 8) # 2, 3, 4, 5, 6, 7
range(0, 20, 3) # 0, 3, 6, 9, 12, 15, 18Un argumento da ; dos dan el intervalo semiabierto ; tres añaden la diferencia común . Por lo decisivo, range es perezoso: registra los parámetros y calcula cada valor solo cuando el bucle lo pide. Pedir un millón de pasos cuesta en memoria lo mismo que pedir cinco, la secuencia jamás se materializa.
Enumerate: la posición, sin el contador
¿Quieres la posición de cada elemento? El instinto de novato es un contador manual:
fruits = ["apple", "banana", "cherry"]
i = 0
for fruit in fruits:
print(f"{i}: {fruit}")
i += 1El i += 1 es una tentación a desincronizarse: olvida uno y las etiquetas de posición se desordenan. enumerate produce ambas mitades en un paso, el índice y el elemento, así que no hay nada que mantener al día:
for i, fruit in enumerate(fruits):
print(f"{i}: {fruit}")
# Los encuestadores numeran a la gente desde 1:
for i, fruit in enumerate(fruits, start=1):
print(f"{i}: {fruit}")Donde un matemático escribe para pegar la posición al valor, enumerate entrega el par directo al cuerpo del bucle.
Zip: alineación por posición
Dos listas paralelas, nombres y notas, suplican leerse juntas. zip las alinea elemento por elemento:
names = ["Alice", "Bob", "Charlie"]
scores = [85, 92, 78]
for name, score in zip(names, scores):
print(f"{name}: {score}")
# Alice: 85
# Bob: 92
# Charlie: 78El emparejamiento es el truco cartesiano de correr por ambas listas con un solo cursor, formando las tuplas . Cuando las listas difieren en longitud, el emparejamiento se detiene en la más corta, así que nada queda a medio emparejar. Si también necesitas la cola torcida, itertools.zip_longest la rellena:
import itertools
for pair in itertools.zip_longest([1, 2], [3, 4, 5], fillvalue=0):
print(pair) # (1, 3), (2, 4), (0, 5) — ninguna valor se pierdeUn ejemplo resuelto: el registro de la clase
Observa cómo se componen las tres herramientas. Una profesora tiene una lista de nombres y una lista paralela de notas, y quiere un informe numerado:
names = ["Dina", "Omar", "Sara"]
scores = [78, 91, 85]
for i, (name, score) in enumerate(zip(names, scores), start=1):
print(f"#{i} {name}: {score}")
# #1 Dina: 78
# #2 Omar: 91
# #3 Sara: 85
print(f"Top score: {max(scores)}") # Top score: 91Lee el encabezado del bucle de dentro hacia afuera: zip empareja cada nombre con su nota; los paréntesis (name, score) desempaquetan ese par; enumerate numera los pares empezando en uno. Cuatro gestos que te habrían costado un contador escrito a mano ahora se leen como la frase que describen, la posición se une al valor, par por par, exactamente como une un índice a cada término.
Errores comunes
rangees excluyente arriba.range(5)produce , cinco números, ninguno igual a . Piensa en intervalo semiabierto, .enumeratesobre un dict. Iterar un dict da sus claves;enumeratenumeraría las claves, no los pares. Usadict.items()cuando quieras clave y valor.zipcon longitudes desiguales. Los elementos más allá de la entrada corta se desvanecen en silencio. Nota la pérdida, o rellena conzip_longest.zipes un iterador de un solo uso. En Python 3,p = zip(a, b)te da un iterador, no una lista:list(p)lo consume, y un segundolist(p)queda vacío. Convierte con prisas conlist(zip(a, b))cuando vayas a volver a visitar los pares.
🧩 Desafíos
🧩 Desafío, piensa primero, luego revela
Usa enumerate para imprimir cada color de colors = ["red", "green", "blue"] con su posición empezando en 1.
💡 Respuesta: for i, color in enumerate(colors, 1): print(f"{i}. {color}"), el argumento start renumera los pares desde uno.
🧩 Desafío, piensa primero, luego revela
Con keys = ["a", "b"] y values = [1, 2], usa zip para construir un diccionario.
💡 Respuesta: dict(zip(keys, values)) → {"a": 1, "b": 2}, los pares alineados se vuelven las entradas del mapeo.
🤔 Preguntas socráticas
- ¿Por qué preferir
rangea deletrear la lista[0, 1, 2, 3, 4]? ¿Qué cambia cuando la lista tendría un millón de números? - Puesto que
zipse detiene en la entrada más corta, ¿cómo detectarías qué lado fue el corto? ¿Cuándo importa esa distinción? - ¿Puede
enumeratepasearse por un dict? ¿Qué numeran exactamente los índices?
✅ Comprobación rápida
1. ¿Qué es list(range(1, 10, 2))?
2. ¿Qué devuelve list(zip([1, 2], [3, 4, 5]))?