Saltar al contenido
🐍 Curso de Python
/

Módulo 1 · Lección 18 de 59

La función range

Generar secuencias de números para recorrerlas con un for, con inicio, fin y paso, incluido el paso negativo.

⏱ 10 min de lectura

El for recorre secuencias, y eso está muy bien cuando tienes una cadena o una lista delante. Pero la mitad de las veces lo que quieres es repetir algo diez veces, o recorrer los números del 1 al 100. Ahí no hay ninguna secuencia que recorrer: hay que fabricarla.

range es la función que la fabrica, y está hecha exactamente para combinarse con for.

range con un solo argumento#

python
for numero in range(5):
        print(numero)
Salida en pantalla
0
1
2
3
4

Cinco vueltas, pero los números van del 0 al 4. Esto es lo primero que hay que interiorizar: range(5) produce cinco números empezando en cero, y el 5 no sale.

range con inicio y fin#

Si el cero no te sirve, di desde dónde empezar:

python
for numero in range(1, 6):
        print(numero)
Salida en pantalla
1
2
3
4
5

El primer argumento es el inicio, incluido; el segundo es el fin, excluido. De ahí el 6 para llegar hasta el 5.

Esta es la forma que usarás para cualquier cosa que se cuente como cuentan las personas, empezando por el uno:

python
for multiplicador in range(1, 11):
        print(f"7 x {multiplicador:>2} = {7 * multiplicador:>3}")
Salida en pantalla
7 x  1 =   7
7 x  2 =  14
7 x  3 =  21
7 x  4 =  28
7 x  5 =  35
7 x  6 =  42
7 x  7 =  49
7 x  8 =  56
7 x  9 =  63
7 x 10 =  70

range con paso#

El tercer argumento es cuánto avanzar en cada salto:

python
for numero in range(0, 21, 5):
        print(numero)
Salida en pantalla
0
5
10
15
20

El paso por defecto es 1, que es lo que se aplicaba en los ejemplos anteriores. Con paso, el final sigue estando excluido: el rango va dando saltos y se detiene en el último número que no alcance el fin. Por eso range(0, 21, 5) llega hasta el 20, mientras que range(0, 20, 5) se queda en el 15.

Paso negativo#

Un paso negativo cuenta hacia atrás. Entonces el inicio tiene que ser mayor que el fin:

python
for numero in range(10, 0, -1):
        print(numero)
Salida en pantalla
10
9
8
7
6
5
4
3
2
1

Ahí está otra vez el fin excluido, y es la trampa habitual: para llegar hasta el 1 hay que poner un 0 como fin. Si de verdad quieres que salga el cero, range(10, -1, -1).

cuenta_atras.py
MINUTOS = 3

for restantes in range(MINUTOS * 60, -1, -30):
        minutos = restantes // 60
    segundos = restantes % 60
    print(f"Quedan {minutos}:{segundos:02d}")

print("Tiempo agotado.")
Salida en pantalla
Quedan 3:00
Quedan 2:30
Quedan 2:00
Quedan 1:30
Quedan 1:00
Quedan 0:30
Quedan 0:00
Tiempo agotado.

range no es una lista#

Imprime un range a secas y verás algo inesperado:

python
print(range(5))
print(type(range(5)))
Salida en pantalla
range(0, 5)
<class 'range'>

No sale [0, 1, 2, 3, 4] porque range no contiene los números: contiene la receta para generarlos. Guarda solo tres datos, el inicio, el fin y el paso, y va calculando cada número en el momento en que el for se lo pide.

Eso es una decisión de diseño deliberada y muy útil: range(1000000) ocupa lo mismo que range(5), unas pocas decenas de bytes, mientras que una lista con un millón de números ocuparía megabytes. Puedes recorrer rangos enormes sin gastar memoria.

Cuando quieras ver el contenido, pide que se construya la lista con list():

python
print(list(range(5)))
print(list(range(1, 6)))
print(list(range(0, 21, 5)))
print(list(range(10, 0, -1)))
print(list(range(5, 1)))
Salida en pantalla
[0, 1, 2, 3, 4]
[1, 2, 3, 4, 5]
[0, 5, 10, 15, 20]
[10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
[]

len() también funciona sobre un range y te dice cuántas vueltas dará el bucle sin necesidad de generarlo:

python
print(len(range(5)))
print(len(range(0, 21, 5)))
Salida en pantalla
5
5

Tabla de referencia#

ExpresiónNúmeros que produceCuántos
range(5)0, 1, 2, 3, 45
range(1, 5)1, 2, 3, 44
range(1, 6)1, 2, 3, 4, 55
range(0, 10, 2)0, 2, 4, 6, 85
range(0, 10, 3)0, 3, 6, 94
range(10, 0, -1)10, 9, 8, ... 2, 110
range(10, -1, -2)10, 8, 6, 4, 2, 06
range(5, 1)ninguno0
range(0, 10, -1)ninguno0

Recorrer un texto por posiciones#

Con range(len(texto)) puedes recorrer las posiciones en lugar de los caracteres, que es lo que necesitas cuando además del carácter te interesa dónde está:

python
palabra = "Python"

for posicion in range(len(palabra)):
        print(f"{posicion}: {palabra[posicion]}")
Salida en pantalla
0: P
1: y
2: t
3: h
4: o
5: n

len(palabra) es 6, así que range(6) da del 0 al 5, que son exactamente las posiciones válidas. El fin excluido encaja aquí de forma perfecta, y no es casualidad: es el motivo por el que se diseñó así.

Los errores de uno de más y uno de menos#

Son tan frecuentes que tienen nombre propio en inglés, off-by-one, y casi siempre salen de olvidar que el final está excluido.

Lo que quieresMalBien
Del 1 al 10range(1, 10) se queda en 9range(1, 11)
Diez vueltasrange(1, 10) da nueverange(10) o range(1, 11)
Las posiciones de un textorange(len(texto) + 1) se salerange(len(texto))
Del 10 al 1 hacia atrásrange(10, 1, -1) se queda en 2range(10, 0, -1)