• iterator._ _iter_ _(): es un método del objeto que devuelve una referencia al mismo objeto;
• iterator._ _next_ _(): es un método que devuelve el elemento siguiente del contenedor, o bien detecta una excepción de tipo StopIteration si los elementos del contenedor han sido todos devueltos.
Un objeto contenedor obj se considera iterable si es posible acceder a sus elementos mediante indexación, o bien si cuenta con un método obj._ _iter_ _() que devuelve un iterador.
Según estas definiciones, un iterador es un objeto iterable, mientras que un objeto iterable no se considera que sea un iterador. Por ejemplo, un conjunto no es un iterador porque no tiene el método set._ _next_ _():
Veamos si es un objeto iterable. En primer lugar, comprobamos que tenga un método set._ _iter_ _():
A continuación, debemos comprobar que este método devuelva un iterador. Si así fuera, el conjunto sería un objeto iterable. Vamos allá:
Ahora falta una condición para poder afirmar que obj es un interador. Su método obj._ _next_ _() debe devolver a cada llamada el elemento siguiente del contenedor y generar una excepción del tipo StopIteration cuando los elementos han terminado:
En definitiva, las instancias del tipo set son objetos iterables porque tienen un método set._ _iter_ _() que devuelve un iterador, pero no son iteradores porque no tienen el método set._ _next_ _().
Las funciones integradas iter() y next() también permiten iterar manualmente sobre un objeto iterable:
Una carácterística importante de los iteradores es que quedan vinculados al objeto iterable:
Profundizaremos en este argumento en el Capítulo 6.
Las clases integradas range y enumerate
En el Capítulo 2 trataremos las funciones integradas vinculadas a los objetos iterables; de momento nos limitamos a hablar únicamente de las clases range y enumerate. La clase range tiene un argumento stop obligatorio y dos argumentos start y step opcionales:
Devuelve un objeto iterable que contiene una secuencia de números progresivos. Cuando se utiliza con el argumento simple stop, el objeto contiene los números del 0 al stop exclusive:
Los argumentos opcionales start y step permiten indicar el número de inicio y el intervalo entre un número y el siguiente:
La clase enumerate toma como argumento un objeto iterable y devuelve un iterador que itera sobre tuplas. Cada tupla está formada por un índice progresivo y por un elemento del objeto iterable. Cuando el objeto iterable es una secuencia seq, el índice progresivo corresponde al índice del elemento en la secuencia, por lo que las tuplas serán (idx, seq[idx]):
Acabamos esta parte demostrando una importante diferencia entre iteradores y objetos iterables que no son iteradores. Mientras que para un objeto iterable que no es un iterador es posible utilizar diferentes iteradores sobre él de manera independiente, esto no es posible para un objeto iterador, puesto que el método iteratore._ _iter_ _() devuelve una referencia a sí mismo:
El contexto de iteración
La instrucción for permite iterar de forma automática sobre los objetos iterables:
De hecho, utiliza el protocolo de iteración para completar automáticamente el proceso que hemos ejecutado manualmente en la sección anterior:
1. obtiene el iterador: iterador = iter(('a', 'b', 'c'));
2. solicita el elemento siguiente llamando al método iterador._ _next_ _();
3. si iterador._ _next_ _() genera una excepción StopIteration, entonces captura la excepción y termina la iteración; si no, pasa al punto 4;
4. asigna a la etiqueta i el elemento siguiente: i = iterador._ _next_ _();
5. ejecuta el bloque de instrucciones, que en este caso son la llamada simple a print(i);
6. regresa al punto 2.
También los diccionarios y los archivos son objetos iterables. Cuando se itera sobre un diccionario, se itera sobre sus claves: :
mientras que cuando se itera sobre un archivo, se itera sobre sus líneas:
Una importante carácterística de los objetos iterables es que pueden ser desempaquetados:
Ejercicio final
En esta sección haremos un ejercicio que nos servirá de resumen, y nos permitirá tanto repasar todo lo que hemos visto hasta ahora como introducir nuevos conceptos. Con este objetivo, vamos a analizar un script que lee archivos con extensión .data, realiza algunos cálculos y, por último, guarda los resultados en otro archivo. El script en cuestión es el archivo dataout.py:
NOTA
El código fuente de todos los ejercicios finales y de los ejemplos más significativos del libro está disponible en la URL http://code.google.com/p/the-pythonic-way/.
Es probable que gran parte de este código nos resulte confuso, pero no nos preocupemos, puesto que lo anlizaremos línea a línea en las secciones siguientes. De momento, volvamos a leerlo y esforcémonos al máximo por entender su significado nosotros solos.
Ejecución del script
El script lee del directorio actual los archivos con extensión .data y para cada uno de ellos crea un archivo de salida con el mismo nombre, pero con extensión .dataout. Por ejemplo, encuentra un archivo