In part 1 of the iterators post, we understood what an iterator is, how it works, the methods it calls, and how it can be used with the iter
method explicitly. If you haven't seen that post, it is strongly suggested to understand those concepts and then come back to this post.
In today's post, we will see how the for
loop automatically iterates through an iterable, how to build your own iterator and the concept of infinite iterators.
1. The for
loop with iterators
The for
loop looks something like this:
for value in data_structure:
print(value)
It can be seen from the for
loop that there is no need to explicitly create an iterator or call the next
method to display the subsequent data elements. This is because for loop has been designed to automatically iterate through any iterable without the need to explicitly call the __iter__
and __next__
methods.
Under the hood, the for loop creates an iterator object by calling the iter()
method on the iterable that is used in the for loop. Inside this loop, the next method is called until all the elements inside the iterable are not covered. Once all the elements are covered, a StopIteration error is raised which is again handled internally by the for loop which results in the ending of the loop. It has been explained in code below:
iter_obj = iter(iterable) # An iterator object is created by passing the iterable (object) to the iter method
while True: # This is an infinite while loop that runs until the last element has been returned
try:
element = next(iter_obj) # The next method to get hold of the next element in the iterable
# do something with the value
except StopIteration: # if StopIteration is raised, break from loop
break
In the code example above, we have used the while
loop to describe the internals of a for
loop in python.
2. Building your own iterators
As trivial as it sounds, building customized iterators isn't a tough task. Just implement the methods that an iterator calls under the hood, i.e __iter__
method, and __next__
method.
The __iter__
method helps in returning the iterator object (if needed, changes, including initialization can be done here) after which the __next__
method is implemented, that helps in returning the next data element present in the iterable sequence. Once all the elements in the sequence are iterated over, the StopIteration error is raised, which is handled on its own.
Below is an example that demonstrates customizing an iterator,
class Studytonight:
def __init__(self, max = 0):
self.max = max
def __iter__(self):
self.n = 0
return self
def __next__(self):
if self.n <= self.max:
result = 12 * self.n
self.n += 1
return result
else:
raise StopIteration
class_instance = Studytonight(2)
i = iter(class_instance)
print(next(i))
print(next(i))
print(next(i))
print(next(i))
Output:
0
12
24
Traceback (most recent call last):
File "<ipython-input-8-716c1e69f048>", line 23, in <module>
print(next(i))
File "<ipython-input-8-716c1e69f048>", line 15, in __next__
raise StopIteration
StopIteration
In addition to calling the next
method, our custom iterator can be used in a for loop too. See below,
for i in Studytonight(3):
print(i)
Output:
0
12
24
36
3. Infinite iterators
There is no rule which says iterators need to be used on an iterable sequence that has finite data elements, there can be infinite iterators as well. Such iterators need to be handled very carefully in case it is used in production-level code. Below is an example, that shows how infinite iterator is used.
The next
method can be called an innumerable number of times and it never raises StopIteration error (in the below code) since the value returned by iter
method will never be equal to 0. Here, we have used the int()
method which returns 0 and it is being compared with the return value of iter method.
print(int())
infinite_iterator = iter(int, 5)
next(infinite_iterator) # call this line how many ever times you wish to, it will never give StopIteration error
Output:
0
What are the advantages of using iterators?
-
They help save resources on the system, by utilizing as less memory as possible.
-
They make the code readable and clean.
Conclusion
In this post, we understood how for loop works with iterators, building one's own iterators and infinite iterators. Iterators play an important role in Python applications. So don't forget to get a hold on these concepts.
You may also like: