What is the most basic definition of \"iterable\", \"iterator\" and \"iteration\" in Python?
I have read multiple definitions but I am unable to identify the exact m
iterable = [1, 2]
iterator = iter(iterable)
print(iterator.__next__())
print(iterator.__next__())
so,
iterable
is an object that can be looped over. e.g. list , string , tuple etc.
using the iter
function on our iterable
object will return an iterator object.
now this iterator object has method named __next__
(in Python 3, or just next
in Python 2) by which you can access each element of iterable.
so, OUTPUT OF ABOVE CODE WILL BE:
1
2
Iterables have a
__iter__
method that instantiates a new iterator every time.Iterators implement a
__next__
method that returns individual items, and a__iter__
method that returnsself
.Therefore, iterators are also iterable, but iterables are not iterators.
Luciano Ramalho, Fluent Python.
Iteration is a general term for taking each item of something, one after another. Any time you use a loop, explicit or implicit, to go over a group of items, that is iteration.
In Python, iterable and iterator have specific meanings.
An iterable is an object that has an __iter__
method which returns an iterator, or which defines a __getitem__
method that can take sequential indexes starting from zero (and raises an IndexError
when the indexes are no longer valid). So an iterable is an object that you can get an iterator from.
An iterator is an object with a next
(Python 2) or __next__
(Python 3) method.
Whenever you use a for
loop, or map
, or a list comprehension, etc. in Python, the next
method is called automatically to get each item from the iterator, thus going through the process of iteration.
A good place to start learning would be the iterators section of the tutorial and the iterator types section of the standard types page. After you understand the basics, try the iterators section of the Functional Programming HOWTO.
I don't think that you can get it much simpler than the documentation, however I'll try:
You can think Iterator as a helper pseudo-method (or pseudo-attribute) that gives (or holds) the next (or first) item in the iterable. (In practice it is just an object that defines the method next()
)
Iteration is probably best explained by the Merriam-Webster definition of the word :
b : the repetition of a sequence of computer instructions a specified number of times or until a condition is met — compare recursion
The above answers are great, but as most of what I've seen, don't stress the distinction enough for people like me.
Also, people tend to get "too Pythonic" by putting definitions like "X is an object that has __foo__()
method" before. Such definitions are correct--they are based on duck-typing philosophy, but the focus on methods tends to get between when trying to understand the concept in its simplicity.
So I add my version.
In natural language,
In Python,
iterable is an object that is, well, iterable, which simply put, means that
it can be used in iteration, e.g. with a for
loop. How? By using iterator.
I'll explain below.
... while iterator is an object that defines how to actually do the
iteration--specifically what is the next element. That's why it must have
next()
method.
Iterators are themselves also iterable, with the distinction that their __iter__()
method returns the same object (self
), regardless of whether or not its items have been consumed by previous calls to next()
.
So what does Python interpreter think when it sees for x in obj:
statement?
Look, a
for
loop. Looks like a job for an iterator... Let's get one. ... There's thisobj
guy, so let's ask him."Mr.
obj
, do you have your iterator?" (... callsiter(obj)
, which callsobj.__iter__()
, which happily hands out a shiny new iterator_i
.)OK, that was easy... Let's start iterating then. (
x = _i.next()
...x = _i.next()
...)
Since Mr. obj
succeeded in this test (by having certain method returning a valid iterator), we reward him with adjective: you can now call him "iterable Mr. obj
".
However, in simple cases, you don't normally benefit from having iterator and iterable separately. So you define only one object, which is also its own iterator. (Python does not really care that _i
handed out by obj
wasn't all that shiny, but just the obj
itself.)
This is why in most examples I've seen (and what had been confusing me over and over), you can see:
class IterableExample(object):
def __iter__(self):
return self
def next(self):
pass
instead of
class Iterator(object):
def next(self):
pass
class Iterable(object):
def __iter__(self):
return Iterator()
There are cases, though, when you can benefit from having iterator separated from the iterable, such as when you want to have one row of items, but more "cursors". For example when you want to work with "current" and "forthcoming" elements, you can have separate iterators for both. Or multiple threads pulling from a huge list: each can have its own iterator to traverse over all items. See @Raymond's and @glglgl's answers above.
Imagine what you could do:
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()
Notes:
I'll repeat again: iterator is not iterable. Iterator cannot be used as
a "source" in for
loop. What for
loop primarily needs is __iter__()
(that returns something with next()
).
Of course, for
is not the only iteration loop, so above applies to some other
constructs as well (while
...).
Iterator's next()
can throw StopIteration to stop iteration. Does not have to,
though, it can iterate forever or use other means.
In the above "thought process", _i
does not really exist. I've made up that name.
There's a small change in Python 3.x: next()
method (not the built-in) now
must be called __next__()
. Yes, it should have been like that all along.
You can also think of it like this: iterable has the data, iterator pulls the next item
Disclaimer: I'm not a developer of any Python interpreter, so I don't really know what the interpreter "thinks". The musings above are solely demonstration of how I understand the topic from other explanations, experiments and real-life experience of a Python newbie.
Iterable:- something that is iterable is iterable; like sequences like lists ,strings etc.
Also it has either the __getitem__
method or an __iter__
method. Now if we use iter()
function on that object, we'll get an iterator.
Iterator:- When we get the iterator object from the iter()
function; we call __next__()
method (in python3) or simply next()
(in python2) to get elements one by one. This class or instance of this class is called an iterator.
From docs:-
The use of iterators pervades and unifies Python. Behind the scenes, the for statement calls iter()
on the container object. The function returns an iterator object that defines the method __next__()
which accesses elements in the container one at a time. When there are no more elements, __next__()
raises a StopIteration exception which tells the for loop to terminate. You can call the __next__()
method using the next()
built-in function; this example shows how it all works:
>>> s = 'abc'
>>> it = iter(s)
>>> it
<iterator object at 0x00A1DB50>
>>> next(it)
'a'
>>> next(it)
'b'
>>> next(it)
'c'
>>> next(it)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
next(it)
StopIteration
Ex of a class:-
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