Las respuestas anteriores son geniales, pero como la mayoría de lo que he visto, no enfatice la distinción lo suficiente para personas como yo.
Además, las personas tienden a ponerse "demasiado pitónicas" al poner definiciones como "X es un objeto que tiene __foo__()
método" antes. Dichas definiciones son correctas: se basan en la filosofía de tipear patos, pero el enfoque en los métodos tiende a interponerse cuando se trata de comprender el concepto en su simplicidad.
Entonces agrego mi versión.
En lenguaje natural,
- La 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, lo que simplemente significa que puede usarse en iteración, por ejemplo, con un for
bucle. ¿Cómo? Mediante el uso de iterador . Te lo explicaré a continuación.
... mientras que el iterador es un objeto que define cómo hacer la iteración, específicamente cuál es el siguiente elemento. Por eso debe tener
next()
método.
Los iteradores también son iterables, con la distinción de que su __iter__()
método devuelve el mismo objeto ( self
), independientemente de si sus elementos han sido consumidos o no por llamadas anteriores a next()
.
Entonces, ¿qué piensa el intérprete de Python cuando ve una for x in obj:
declaración?
Mira, un for
bucle. Parece un trabajo para un iterador ... Consigamos uno. ... Está este obj
tipo, así que preguntémosle.
"Sr. obj
, ¿tiene su iterador?" (... llamadas iter(obj)
, llamadas
obj.__iter__()
, que felizmente reparte un nuevo iterador brillante _i
).
OK, eso fue fácil ... Comencemos iterando entonces. ( x = _i.next()
... x = _i.next()
...)
Como Mr. obj
tuvo éxito en esta prueba (al hacer que cierto método devuelva un iterador válido), lo recompensamos con un adjetivo: ahora puede llamarlo "Mr. iterable obj
".
Sin embargo, en casos simples, normalmente no se beneficia de tener iterador e iterable por separado. Por lo tanto, define solo un objeto, que también es su propio iterador. (A Python realmente no le importa que lo _i
entregado obj
no fuera tan brillante, sino solo el obj
mismo).
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), puede ver:
class IterableExample(object):
def __iter__(self):
return self
def next(self):
pass
en vez 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 del 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. Ver las respuestas de @ Raymond 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é nuevamente: el iterador no es iterable . Iterator no se puede utilizar como "fuente" en for
bucle. Lo que el for
bucle necesita principalmente es __iter__()
(que devuelve algo con next()
).
Por supuesto, for
no es el único ciclo de iteración, por lo que lo anterior también se aplica a algunas otras construcciones ( while
...).
Los iteradores next()
pueden lanzar 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
realmente no existe. He inventado ese nombre.
Hay un pequeño cambio en Python 3.x: next()
ahora se debe invocar el método (no el incorporado) __next__()
. Sí, debería haber sido así todo el tiempo.
También puede pensarlo así: 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 en Python.
collections.abc.AsyncIterator
pruebas__aiter__
y los__anext__
métodos. Esta es una nueva adición en 3.6.