Iterator in Python: A simple Introduction

Everyone uses the iterator, but most of the time, without knowing about it. For example, we use list, dictionary, string regularly, and all these containers use the iterator behind the scenes.
Let’s dig into iterator today and grasp the main idea of it. First, to understand iterator, we need to understand Iterable.
What is Iterable?
We can say something as iterable when it can iterate(loop over). In simple words, if you can use an object in a for loop to iterate, then you can tell it is iterable. For example, the string is iterable, because we can iterate through a string index by index. Almost all container in python is iterable. List, string, tuple, dictionary are some examples of iterable.
Another essential point is Iterable implements a method __iter__(), returns an iterator object. which is the main part, because, to iterate over an iterable(like string, list) we need an iterator. Don’t get confused, we will explain it. :)
Now, what is Iterator?
An iterator is an object which remembers or stores the state of Iteration. With the __next__() method, an iterator can return the next value of the iteration. __next__() also raise an exception name StopIteration when there is no item to iterate.
Every Iterator is iterable but not all iterable are iterator. Get Confused? No problem, we will explain it.
For example, the string is an iterable but not an iterator. To get an Iterator from an Iterable, we need to use the iter() method. A simple code example will clear this.
here, we declare a string that is iterable.
string = 'Medium'
now, we use the iter() method to get an iterator(iter_obj) from this string.
iter_obj = iter(string)
Note: we use iter() and __iter__() interchangeably, are they same? Yes and No. Yes because iter() function actually call the __iter__() method internally. And No, because they have little differences but we don’t need to explore about it now. lets stick with the main point.
Now using the iter_obj, we can iterate over the string characters using next() method. Here next() function actually call the __next__() method implicitly. we can also call iter_obj.__next__() instead of next(iter_obj) here.
print(next(iter_obj)) # M
print(iter_obj.__next__()) # e
print(iter_obj.__next__()) # d
print(next(iter_obj)) # i
print(next(iter_obj)) # u
print(next(iter_obj)) # m
Here all the elements of the string are iterated, now if you call the next() method then it will raise a StopIteration exception. Let's check it out.
print(next(iter_obj)) # raise a StopIteration exception
we will get an exception like this.
File “02_iterator.py”, line 39, in <module>
print(next(iter_obj)) # raise a StopIteration exception
StopIteration
To summarize the whole thing. we can say,
Iterable is an object which can iterate. like string, list are iterable. we can get an iterator from an iterable using iter() method. in our case, we get an iterator(iter_obj) using the iter() method from the string object.
Custom Iterator
Now let’s dig into a little deeper by creating a custom iterator. Making a custom Iterator in python is not a difficult task. we just need to implement two methods __iter__() and __next__(). that’s all.
Here, SqurareAll is a class that takes a max value on initialization and square all numbers 1 to the max. On doing this we implement the Iterator.
class SquareAll:# contructor
def __init__(self, max=0):
self.current = 1
self.max = maxdef __iter__(self):
return self
def __next__(self):
if self.current <= self.max:
sqr_val = self.current * self.current
self.current += 1
return sqr_val
else:
raise StopIteration
First, we need to initiate an object from the SquareAll class.
sqr_obj = SquareAll(max=5)
Now, we can get all the square value from 1 to 5 using the next() method.
print(next(sqr_obj_iterator)) # 1
print(next(sqr_obj_iterator)) # 4
print(next(sqr_obj_iterator)) # 9
print(next(sqr_obj_iterator)) # 16
print(next(sqr_obj_iterator)) # 25
print(next(sqr_obj_iterator)) # raise a StopIterator expection
So, here we create a custom iterator implementing the __next__() and __iter__() method. then the later process is the same as the previous example of the string. because string and our custom class (SquareAll) both are iterable and both implement the __iter__() and __next__() method.
And this custom iterable (SquareAll) behave exactly the same in a built-in iterable type (string, list, dictionary, etc.) in a for loop. check this code example.
sqr_obj = SquareAll(max=5) # iterablefor item in sqr_obj:
print(item) # print 1 4 9 16 25
So, by implementing, __iter__() and __next__() method, we will get the same result as other built-in iterable types objects like string and list. isn’t it Interesting !!! :)
Hope this will clear your confusion about iterator. Now, one last thing, How for loop iterate over something?
Actually, in the background, for loop create an iterator object and using a while loop which calls next() method continuously to iterate over a sequence until a StopIterator expectation arises. Below pseudo-code explain the process.
iterator_object = iter(some_iterable_object)while True:
try:
item = next(iterator_object)
except StopIteration:
break
So, For loop is nothing but an infinite while loop with StopIterator exception. :P
For More Information …
Python | Difference between iterable and iterator