Python Iterators

    In this tutorial, we will learn what iterators are in Python and where we use them. We will also discuss how we can create our own Python iterators using __iter__ and __next__ methods.

    What is Python Iterators?

    Iterators are the objects in Python that are used to iterate over a collection of values. The most common iterator in Python is the for loop. A for loop statement iterates through an iterable such as string, list, tuple, and dictionary. Iterating means the iterator traverses every value of the iterable. When we use a for iterator, we see that it returns one value at a time because iterators can return only one value. Though the for loop is an inbuilt iterator in Python, according to the Python iterator protocol, each iterator should have two magical methods, _ _iter__() and __next__() . Each iterator needs an iterable to iterate upon, and Python has built-in iterables like strings, lists, tuples, and dictionaries.

    Iterating Through an Iterator

    To iterate through an Iterable , we can use two iterator functions, next() and iter() . The iter() function invokes the __iter__() method and returns an iterator. The next() function is used to iterate upon the iterator. It invokes all the values of the iterator one by one, and if we call the next() function when there is no value left to iterate, then it would throw a StopIteration error.

    Example:

    my_iterable = [1,2,3,4,5]               #we can not perform next() function on iterables
    create_iterator = iter(my_iterable)          #it return a iterator with values
    print(next(create_iterator))        #the next poiner is at 1 index
    print(next(create_iterator))        #the next pointer is at 2 index
    print(next(create_iterator))        #the next pointer is at 3 index
    print(next(create_iterator))        #the next pointer is at 4 index
    print(next(create_iterator))        #the next pointer is at 5 index
    print('------------------After Iterating through all values-----------------')
    print(next(create_iterator))        # there are no more values present in the iterator to iterate so it will throw an error

    Output:

    1
    2
    3
    4
    5
    ------------------After Iterating through all values-----------------
    Traceback (most recent call last):
    StopIteration 

    Behind the Code

    In the above code, first, we use the iter() function to create an iterator, which we assign to a variable name, create_iterator. Then we use the next() function to iterate through every value of that iterator. In the above example, we can see that every time the next() function returns the next value of the iterator and when it iterates through all the values, and there is no more value left to iterate, it throws an error.

    Note : We can perform the same action using a for loop and without an error.

    How does the for Loop Work?

    The for loop is an inbuilt python iterator and can iterate through any kind of iterable. It also uses iter() and next() methods to perform the iteration.

    For Loop Syntax:

    for values in iterable:
        pass

    For Loop Inner Working:

    iterator_object= iter(iterable)
    while True:
        try:
            values= next(iterator_object)
        except StopIteration:    #Once all the values are iterated
            break

    Building Our Own Iterators

    With the help of __iter()__ and __next__() methods, we can create our own iterators.

    Example:

    class multhree:
    """this class create an iterator of multiple of three"""
    
        def __init__(self,m=0):
           self.m=m
    
        def __iter__(self):
            self.n=1
            return self
    
        def __next__(self):
            if self.n <=self.m:
                r = 3*self.n
                self.n+=1
                return r
            else:
                raise StopIteration("NO more elements to iterate")
    
    c_o= multhree(6)
    i =iter(c_o)
    print(next(i))
    print(next(i))
    print(next(i))
    print(next(i))
    print(next(i))
    print(next(i))
    print(next(i))

    Output:

    3
    6
    9
    12
    15
    18
    Traceback (most recent call last):
    StopIteration: NO more elements to iterate

    Python Infinite Iterators

    While creating an iterator in Python, we need to make sure that it must terminate at some value. If we do not give our iterator a terminating point, it will become an infinite iterator, which will have infinite values to access.

    Example:

    class multhree:
      """this class create an iterator of multiple of three"""
        def __init__(self,m=0):
            self.m=m
    
        def __iter__(self):
            self.n=1
            return self
               
        def __next__(self):
            r = 3*self.n
            self.n+=1
            return r                         
    
    c_o= multhree(6)
    i =iter(c_o)
    print(next(i))
    print(next(i))
    print(next(i))
    print(next(i))
    print(next(i))
    print(next(i))
    print(next(i))

    Output:

    3
    6
    9
    12
    15
    18
    21

    Behind the Code

    In the above program, we have passed 6 as an argument to the class multhree() , and we were only hoping for 6 multiples of three, but the iterator is generating more values than we wanted. This can cause many problems.

    Conclusion

    That was all about Python iterators. These are very useful programming entities in Python programming. However, we must make sure to define some termination value. Else we will get an infinite iterator.