Iterators

Iterators

ยท

4 min read

  • In Python, an iterator is an object that enables traversal over a collection of items, one at a time.

  • It follows the iterator protocol, which involves implementing the __iter__() and __next__() methods.

  • The __iter__() method returns the iterator object itself, while __next__() retrieves the next element from the collection.

  • When there are no more elements, a StopIteration exception is raised.

Iterating over lists

Approach -1: Iterating over the list directly

list = [2, 4, 6, 8, 10]
for value in list:
    print(value, end=' ')
#Output = 2 4 6 8 10
  • In this approach, the entire list [2, 4, 6, 8, 10] is stored in memory.

  • The for loop iterates over each element of the list, processing them one by one.

  • Memory usage is relatively higher since the complete list is stored in memory throughout the loop execution.

Approach -2: Using an iterator object

list = [2, 4, 6, 8, 10]
iter_obj = iter(list) # <list_iterator object at 0x7fcf3519f670>
print(next(iter_obj)) # Output = 2
print(next(iter_obj))# Output = 4
print(next(iter_obj))# Output = 6
print(next(iter_obj))# Output = 8
print(next(iter_obj))# Output = 10
  • In this approach, an iterator object is explicitly created using iter(list).

  • Each call to next(iter_obj) retrieves the next element from the iterator, without storing the entire list in memory.

  • Only one element at a time is accessed and processed, reducing memory usage.

  • As elements are fetched one by one, the memory footprint is lower compared to

Built-in Iterators in Python

Python provides several built-in iterators and iterable objects that simplify common iteration tasks. Let's explore a few of them:

  1. range()

    The range() function generates a sequence of numbers within a specified range. It can be used directly as an iterator.

     for i in range(5):
         print(i,end = " ")
     #Output = 0 1 2 3 4 5
    
  2. enumerate()

    The enumerate() function is useful when we need both the index and value of each element while iterating over a sequence.

     my_list = ['Nirmal', 'Niraj', 'Retrica']
     for index, value in enumerate(my_list):
         print(f"Index: {index}, Value: {value}")
    

    Output :

     Index: 0, Value: nirmal
     Index: 1, Value: niraj
     Index: 2, Value: retrica
    
  3. zip():

    The zip() function combines multiple iterables into a single iterator. It pairs up corresponding elements from each iterable.

     names =  ['Nirmal', 'Niraj', 'Retrica']
     ages = [23, 20, 27]
    
     for name, age in zip(names, ages):
         print(f"Name: {name}, Age: {age}")
    

    Output :

     Name: Nirmal, Age: 23
     Name: Niraj, Age: 20
     Name: Retrica, Age: 27
    

Itertools Module

The itertools module is a powerful tool that provides various functions for efficient iteration and a combination of iterables. It extends the capabilities of built-in iterators.

Some modules are :

1. itertools.cycle()

This creates an iterator that cycles through elements of an iterable indefinitely.

import itertools

name = ["nirmal", "niraj", "retrica"]
myloopy = itertools.cycle(name)

print(next(myloopy))  # Output: nirmal
print(next(myloopy))  # Output: niraj
print(next(myloopy))  # Output: retrica

2. itertools.chain()

This combines multiple iterables into a single sequence.

import itertools

inter1 = itertools.chain("nirmal", "pandey")
print(list(inter1))  # Output: ['n', 'i', 'r', 'm', 'a', 'l', 'p', 'a', 'n', 'd', 'e', 'y']
  1. itertools. accumulate()

This returns an iterator that produces accumulated sums of an iterable.

import itertools

num = [1, 2, 3, 4, 5, 6]
inter2 = itertools.accumulate(num)
print(list(inter2))  # Output: [1, 3, 6, 10, 15, 21]

4.itertools.repeat()

This generates an iterator that repeats a value a specified number of times.

import itertools

inter3 = itertools.repeat(10, 3)
print(list(inter3))  # Output: [10, 10, 10]

5: itertools.compress()

This filters an iterable based on the truth value of corresponding selectors.

import itertools

inter4 = itertools.compress("nirmal", [1, 0, 1, 0, 1, 1])
print(list(inter4))  # Output: ['n', 'r', 'a', 'l']

Custom Iterator

class MyIterator:
    def __init__(self, data):
        self.data = data
        self.index = 0

    def __iter__(self):
        return self

    def __next__(self):
        if self.index >= len(self.data):
            raise StopIteration
        value = self.data[self.index]
        self.index += 1
        return value


my_list = [1, 2, 3, 4, 5]
my_iter = MyIterator(my_list)

for item in my_iter:
    print(item)

In this example, we create a custom iterator MyIterator takes a list as input. The __iter__() method returns the iterator object itself, and __next__() fetches the next element from the list. Once there are no more elements, a StopIteration exception is raised.

ย