¿Qué son exactamente iterador, iterable e iteración?

¿Cuál es la definición más básica de “iterable“, “iterador” e “iteración” en Python?

He leído varias definiciones, pero no puedo identificar el significado exacto ya que aún no puedo entenderlo.

¿Puede alguien ayudarme con las 3 definiciones en términos sencillos?

Iteración es un término general para tomar cada elemento de algo, uno tras otro. Cada vez que use un bucle, explícito o implícito, para repasar un grupo de elementos, eso es iteración.

En Python, iterable e iterador tienen significados específicos.

Un iterable es un objeto que tiene un método __iter__ que devuelve un iterador , o que define un método __getitem__ que puede tomar índices secuenciales comenzando desde cero (y genera un IndexError cuando los índices ya no son válidos). Por lo tanto, un objeto iterable es un objeto del que puede obtener un iterador .

Un iterador es un objeto con un método next (Python 2) o __next__ (Python 3).

Siempre que use un bucle for , un map , una lista de comprensión, etc. en Python, se llama automáticamente al next método para obtener cada elemento del iterador , y así pasar por el proceso de iteración .

Un buen lugar para comenzar a aprender sería la sección de iteradores del tutorial y la sección de tipos de iteradores de la página de tipos estándar . Después de comprender los conceptos básicos, pruebe la sección de iteradores del CÓMO de progtwigción funcional .

Aquí está la explicación que utilizo para enseñar clases de Python:

Un ITERABLE es:

  • cualquier cosa que se pueda pasar en bucle (es decir, se puede hacer un bucle en una cadena o archivo) o
  • cualquier cosa que pueda aparecer en el lado derecho de un bucle for x in iterable: ... : for x in iterable: ... o
  • cualquier cosa que pueda llamar con iter() que devolverá un ITERATOR: iter(obj) o
  • un objeto que define __iter__ que devuelve un ITERATOR nuevo, o puede tener un método __getitem__ adecuado para la búsqueda indexada.

Un ITERATOR es un objeto:

  • con estado que recuerda dónde está durante la iteración,
  • con un método __next__ que:
    • Devuelve el siguiente valor en la iteración.
    • actualiza el estado para que apunte al siguiente valor
    • Señala cuando se hace levantando StopIteration
  • y eso es auto-iterable (lo que significa que tiene un método __iter__ que devuelve self ).

Notas:

  • El método __next__ en Python 3 se escribe a next en Python 2, y
  • La función incorporada next() llama a ese método en el objeto que se le pasa.

Por ejemplo:

 >>> s = 'cat' # s is an ITERABLE # s is a str object that is immutable # s has no state # s has a __getitem__() method >>> t = iter(s) # t is an ITERATOR # t has state (it starts by pointing at the "c" # t has a next() method and an __iter__() method >>> next(t) # the next() function returns the next value and advances the state 'c' >>> next(t) # the next() function returns the next value and advances 'a' >>> next(t) # the next() function returns the next value and advances 't' >>> next(t) # next() raises StopIteration to signal that iteration is complete Traceback (most recent call last): ... StopIteration >>> iter(t) is t  # the iterator is self-iterable 

Las respuestas anteriores son excelentes, pero como la mayoría de lo que he visto, no enfatice la distinción lo suficiente para las personas como yo.

Además, las personas tienden a ponerse “demasiado Pythonic” al colocar definiciones como “X es un objeto que tiene el __foo__() ” antes. Tales definiciones son correctas, se basan en la filosofía de tipificación de pato, pero el enfoque en los métodos tiende a interponerse cuando se trata de entender el concepto en su simplicidad.

Así que añado mi versión.


En lenguaje natural,

  • iteración es el proceso de tomar un elemento a la vez en una fila de elementos.

En Python,

  • iterable es un objeto que es, bueno, iterable, que en pocas palabras significa que se puede usar en iteración, por ejemplo, con un bucle for . ¿Cómo? Mediante el uso de iterador . Voy a explicar a continuación.

  • … mientras que iterador es un objeto que define cómo realizar la iteración, específicamente cuál es el siguiente elemento. Es por eso que debe tener el método next() .

Los iteradores también son iterables, con la distinción de que su __iter__() devuelve el mismo objeto ( self ), independientemente de si sus elementos han sido consumidos o no por las llamadas anteriores a next() .


Entonces, ¿qué piensa el intérprete de Python cuando ve for x in obj: statement?

Mira, un bucle for . Parece un trabajo para un iterador … Consigamos uno. … Hay un tipo obj , así que vamos a preguntarle.

“Sr. obj , ¿tiene su iterador?” (… llama a iter(obj) , que llama a obj.__iter__() , que felizmente entrega un nuevo iterador shiny _i .)

OK, eso fue fácil … Empecemos iterando entonces. ( x = _i.next()x = _i.next() …)

Como el Sr. obj tuvo éxito en esta prueba (al tener cierto método para devolver un iterador válido), lo recompensamos con un adjetivo: ahora puede llamarlo “iterable Sr. obj “.

Sin embargo, en casos simples, normalmente no se beneficia de tener iterador e iterable por separado. Así que solo define un objeto, que también es su propio iterador. (A Python realmente no le importa que lo que _i entregué por obj no fuera tan shiny, sino solo el propio obj ).

Es por eso que en la mayoría de los ejemplos que he visto (y lo que me había estado confundiendo una y otra vez), puedes ver:

 class IterableExample(object): def __iter__(self): return self def next(self): pass 

en lugar de

 class Iterator(object): def next(self): pass class Iterable(object): def __iter__(self): return Iterator() 

Sin embargo, hay casos en los que puede beneficiarse de tener un iterador separado de lo iterable, como cuando desea tener una fila de elementos, pero más “cursores”. Por ejemplo, cuando desea trabajar con elementos “actuales” y “próximos”, puede tener iteradores separados para ambos. O múltiples hilos que se extraen de una gran lista: cada uno puede tener su propio iterador para recorrer todos los elementos. Vea las respuestas de @Raymond’s y @glglgl arriba.

Imagina lo que podrías hacer:

 class SmartIterableExample(object): def create_iterator(self): # An amazingly powerful yet simple way to create arbitrary # iterator, utilizing object state (or not, if you are fan # of functional), magic and nuclear waste--no kittens hurt. pass # don't forget to add the next() method def __iter__(self): return self.create_iterator() 

Notas:

  • Repetiré de nuevo: el iterador no es iterable . El iterador no se puede usar como “fuente” en el bucle for . Lo for necesita principalmente el bucle es __iter__() (que devuelve algo con next() ).

  • Por supuesto, for no es el único bucle de iteración, así que lo anterior también se aplica a algunas otras construcciones ( while …).

  • El next() del iterador puede lanzar la función StopIteration para detener la iteración. Sin embargo, no tiene que hacerlo, puede iterar para siempre o usar otros medios.

  • En el “proceso de pensamiento” anterior, _i no existe realmente. Me he inventado ese nombre.

  • Hay un pequeño cambio en Python 3.x: el método next() (no el incorporado) ahora debe llamarse __next__() . Sí, debería haber sido así todo el tiempo.

  • También puedes pensar en esto de la siguiente manera: iterable tiene los datos, el iterador extrae el siguiente elemento

Descargo de responsabilidad: no soy desarrollador de ningún intérprete de Python, por lo que realmente no sé qué “piensa” el intérprete. Las reflexiones anteriores son únicamente una demostración de cómo entiendo el tema a partir de otras explicaciones, experimentos y experiencias de la vida real de un novato de Python.

Un iterable es un objeto que tiene un __iter__() . Posiblemente puede repetirse varias veces, como list() sy tuple() s.

Un iterador es el objeto que itera. Se devuelve mediante un __iter__() , se devuelve a sí mismo a través de su propio __iter__() y tiene un método next() ( __next__() en 3.x).

La iteración es el proceso de llamar a este next() resp. __next__() hasta que StopIteration .

Ejemplo:

 >>> a = [1, 2, 3] # iterable >>> b1 = iter(a) # iterator 1 >>> b2 = iter(a) # iterator 2, independent of b1 >>> next(b1) 1 >>> next(b1) 2 >>> next(b2) # start over, as it is the first call to b2 1 >>> next(b1) 3 >>> next(b1) Traceback (most recent call last): File "", line 1, in  StopIteration >>> b1 = iter(a) # new one, start over >>> next(b1) 1 

No sé si ayuda a alguien, pero siempre me gusta visualizar conceptos en mi cabeza para entenderlos mejor. Entonces, como tengo un hijo pequeño, visualizo el concepto iterativo / iterador con ladrillos y papel blanco.

Supongamos que estamos en el cuarto oscuro y en el piso tenemos ladrillos para mi hijo. Ladrillos de diferente tamaño, color, no importa ahora. Supongamos que tenemos 5 ladrillos como esos. Esos 5 ladrillos se pueden describir como un objeto , digamos kit de ladrillos . Podemos hacer muchas cosas con este kit de ladrillos: podemos tomar uno y luego tomar el segundo y luego el tercero, podemos cambiar los lugares de ladrillos, poner el primer ladrillo por encima del segundo. Podemos hacer muchos tipos de cosas con esos. Por lo tanto, este kit de ladrillos es un objeto o secuencia iterable , ya que podemos atravesar cada ladrillo y hacer algo con él. Solo podemos hacerlo como mi pequeño hijo: podemos jugar con un ladrillo a la vez . Así que de nuevo me imagino que este kit de ladrillos es un iterable .

Ahora recuerda que estamos en el cuarto oscuro. O casi a oscuras. El problema es que no vemos claramente esos ladrillos, qué color son, qué forma, etc. Entonces, incluso si queremos hacer algo con ellos, también conocido como iterar a través de ellos , realmente no sabemos qué y cómo porque es demasiado oscuro.

Lo que podemos hacer es acercarnos al primer ladrillo, como elemento de un juego de ladrillos, podemos poner un trozo de papel blanco fluorescente para que podamos ver dónde está el primer elemento de ladrillo. Y cada vez que sacamos un ladrillo de un kit, reemplazamos el trozo de papel blanco por el siguiente ladrillo para poder ver eso en el cuarto oscuro. Este pedazo de papel blanco no es más que un iterador . También es un objeto . Pero un objeto con el que podemos trabajar y jugar con elementos de nuestro objeto iterable: el kit de ladrillos.

Por cierto, eso explica mi error inicial cuando probé lo siguiente en un IDLE y obtuve un TypeError:

  >>> X = [1,2,3,4,5] >>> next(X) Traceback (most recent call last): File "", line 1, in  next(X) TypeError: 'list' object is not an iterator 

Lista X aquí estaba nuestro kit de ladrillos pero NO un papel blanco. Necesitaba encontrar un iterador primero:

 >>> X = [1,2,3,4,5] >>> bricks_kit = [1,2,3,4,5] >>> white_piece_of_paper = iter(bricks_kit) >>> next(white_piece_of_paper) 1 >>> next(white_piece_of_paper) 2 >>> 

No sé si ayuda, pero me ayudó. Si alguien pudiera confirmar / corregir la visualización del concepto, estaría agradecido. Me ayudaría a aprender más.

Aquí está mi hoja de trucos:

  sequence + | v def __getitem__(self, index: int): + ... | raise IndexError | | | def __iter__(self): | + ... | | return  | | | | +--> or <-----+ def __next__(self): + | + ... | | | raise StopIteration v | | iterable | | + | | | | v | +----> and +-------> iterator | ^ v | iter() +----------------------+ | def generator(): | + yield 1 | | generator_expression +-+ | | +-> generator() +-> generator_iterator +-+ 

Cuestionario: ¿Ves cómo …

  • Cada iterador es un iterable?
  • ¿Se puede implementar el método __iter__() un objeto contenedor como un generador?
  • ¿ __next__ método iterable más un método __next__ no es necesariamente un iterador?

No creo que puedas obtenerlo mucho más simple que la documentación , pero intentaré:

  • Iterable es algo que puede ser iterado . En la práctica, usualmente significa una secuencia, por ejemplo, algo que tiene un principio y un final y alguna forma de revisar todos los elementos que contiene.
  • Puede pensar en Iterator como un pseudo-método auxiliar (o pseudo-atributo) que da (o retiene) el siguiente (o primer) elemento en el iterable . (En la práctica, es solo un objeto que define el método next() )

  • La iteración es probablemente mejor explicada por la definición de Merriam-Webster de la palabra :

b: la repetición de una secuencia de instrucciones de computadora un número específico de veces o hasta que se cumpla una condición – compare la recursión

Iterable : – algo que es iterable es iterable; me gusta secuencias como listas, cadenas, etc. También tiene el __getItem__() o una función iter() que devuelve un iterador.

Iterador : – Cuando obtenemos el objeto iterador del método iter() de iterable; Llamamos al __next__() (en python3) o simplemente next() (en python2) para obtener los elementos uno por uno. Esta clase o instancia de esta clase se llama un iterador.

De los documentos: –

El uso de iteradores impregna y unifica Python. Detrás de escena, la instrucción for llama a iter() en el objeto contenedor. La función devuelve un objeto iterador que define el método __next__() que accede a los elementos en el contenedor de uno en uno. Cuando no hay más elementos, __next__() genera una excepción StopIteration que le dice al bucle for que termine. Puede llamar al __next__() usando la función incorporada next() ; Este ejemplo muestra cómo funciona todo:

 >>> s = 'abc' >>> it = iter(s) >>> it  >>> next(it) 'a' >>> next(it) 'b' >>> next(it) 'c' >>> next(it) Traceback (most recent call last): File "", line 1, in  next(it) StopIteration 

Ex de una clase: –

 class Reverse: """Iterator for looping over a sequence backwards.""" def __init__(self, data): self.data = data self.index = len(data) def __iter__(self): return self def __next__(self): if self.index == 0: raise StopIteration self.index = self.index - 1 return self.data[self.index] >>> rev = Reverse('spam') >>> iter(rev) <__main__.Reverse object at 0x00A1DB50> >>> for char in rev: ... print(char) ... m a p s 
 iterable = [1, 2] iterator = iter(iterable) print(iterator.__next__()) print(iterator.__next__()) 

asi que,

  1. iterable es un objeto que puede ser colocado en bucle . por ejemplo, lista, cadena, tupla, etc.

  2. el uso de la función iter en nuestro objeto iterable devolverá un objeto iterador.

  3. ahora este objeto iterador tiene un método llamado __next__ (en Python 3, o simplemente el next en Python 2) mediante el cual puede acceder a cada elemento de iterable.

Así, el CÓDIGO DE SALIDA DE ARRIBA SERÁ:

1

2

Antes de tratar con los iterables y el iterador, el factor principal que decide el iterable y el iterador es la secuencia.

Secuencia: Secuencia es la recostackción de datos.

Iterable: Iterable es el objeto de tipo de secuencia que admite el método Iter.

Iter method: Iter method toma la secuencia como entrada y crea un objeto conocido como iterador

Iterador: Iterador es el objeto que llama al método siguiente y transversal a través de la secuencia. Al llamar al método siguiente, devuelve el objeto que transversalmente está.

ejemplo:

 x=[1,2,3,4] 

x es una secuencia que consiste en la recostackción de datos

 y=iter(x) 

Al llamar a iter (x), devuelve un iterador solo cuando el objeto x tiene un método iter, de lo contrario, genera una excepción. Si devuelve el iterador, entonces y se asigna de esta forma:

 y=[1,2,3,4] 

Como y es un iterador, soporta el método next ()

Al llamar al siguiente método, devuelve los elementos individuales de la lista uno por uno.

Después de devolver el último elemento de la secuencia, si volvemos a llamar al siguiente método, se genera un error StopIteration

ejemplo:

 >>> y.next() 1 >>> y.next() 2 >>> y.next() 3 >>> y.next() 4 >>> y.next() StopIteration 

Iterables tiene un método __iter__ que __iter__ una instancia de un nuevo iterador cada vez.

Los iteradores implementan un método __next__ que devuelve elementos individuales, y un método __iter__ que se devuelve a self .

Por lo tanto, los iteradores también son iterables, pero los iterables no son iteradores.

Luciano Ramalho, Pitón Fluido.

En Python todo es un objeto. Cuando se dice que un objeto es iterable, significa que puede recorrer (es decir, iterar) el objeto como una colección.

Las matrices, por ejemplo, son iterables. Puede recorrerlos con un bucle for, y pasar del índice 0 al índice n, siendo n la longitud del objeto de la matriz menos 1.

Los diccionarios (pares de clave / valor, también llamados arrays asociativos) también son iterables. Puedes pasar por sus llaves.

Obviamente los objetos que no son colecciones no son iterables. Un objeto bool, por ejemplo, solo tiene un valor, Verdadero o Falso. No es iterable (no tendría sentido que sea un objeto iterable).

Lee mas. http://www.lepus.org.uk/ref/companion/Iterator.xml