Función range
La conocida función “range” de Python, que nos enseñaron en nuestros inicios de programación a usar en un bucle “for”, es posible que en muchas ocasiones la podamos sustituir por mejores opciones y con un código más limpio y moderno. Esta función tiene su origen en los lenguajes C/C++/Java, predecesores de este lenguaje de programación, y que realmente necesitan una variable de bucle de índice, pero en este lenguaje de programación no es necesario tener este índice.
El bucle para una secuencia iterable suele ser así:
for x in range(len(seq)):
#haz_algo_con (seq[x])
La variable x se utiliza solo para acceder al siguiente elemento desde el iterable. Dado que Python “for” es un bucle “foreach”, yo creo, que hay una mejor manera de hacer esto; iterando directamente sobre el iterable (de ahí el nombre) y que quedaría de esta manera:
for cosa in secuencia:
#Haz_algo_con (cosa)
Lo que en un caso sencillo quedaría de esta manera:

y daría el resultado esperado para cada valor en la iteración y usando el valor definido en la secuencia:
>>27
>>64
Esta manera de iteración directa es aproximadamente un 30% más rápido, no requiere crear los índices y es más fácil de leer el código (“para [cada] elemento en [esa] secuencia, haga algo con [ese elemento).
Función Enumerate
Para modificar cada elemento en un iterable mutable, tampoco tenemos problema por no tener índice. En ese caso tenemos otra función disponible: “enumerate”, que nos devuelve un generador que produce tuplas de elementos y sus respectivos índices en la forma (x,seq[x]).
Veamos el código de un caso muy simple:
for x, cosa in enumerate(seq):
seq[x] = do_something_with(item)
Vamos a hacerlo con un caso sencillo, donde lo que hacemos es que se eleve al cubo, teniendo en cuenta que usamos una cadena para la iteración y por tanto el índice empieza en 0 y los números de iteración vienen y es similar al anterior ejemplo:

Obtenemos el índice y el resultado siguiente:
0 0
1 1
2 8
3 27
La función “enumerate” nos da muchas ventajas y puede usarse para varios procesos, que aquí no vamos a detallar y os animo a explorar.
Se puede pensar que se requiere “range” para manipular iterables paralelos, como por ejemplo coordenadas. Veamos un ejemplo, donde las cadenas X e Y almacenan las coordenadas de los puntos bidimensionales.
En este caso, si escribimos el código de esta manera:

Obtenemos un sistema de coordenadas cuyo resultado es:
1 b
2 a
Si queremos profundizar tenemos otras posibilidades, como este otro ejemplo simple, en el que usamos tuplas:

Conseguimos un resultado como este:
(‘Nombre’, ‘Juan’)
(‘Primer apellido’, ‘Lopez’)
(‘Segundo apellido’, ‘Garcia’)
Vemos que Python nos permite múltiples formas de hacer la misma cosa y remitiéndonos al zen de Python (import this) podemos decir:” Now is better than never.”