×

Iterator Design Pattern with Python

Iterator Design Patterns Python Feature

Iterator is a behavioral design pattern that allows sequential traversal through a complex data structure without exposing its internal details.

As we know iteration simply means to traverse any data structure like list, tuple, or dictionary. And, iteration(traversal) is a core functionality of all the data structures.

In python as we know iterable objects have:

  • __iter__() method – Used to convert an iterable to iterator.
  • __next__() method – Method that returns each of the iterated element.
  • And, StopIteration exception to stop iteration.

Example:

st = "PythonWife"
st = iter(st)

while True:
    try:
        print(next(st))

    except StopIteration:
        break
Output:
P
y
t
h
o
n
W
i
f
e

Similar to iteration, Iterator Design Pattern suggests creating an interface that can facilitate the traversal of various entities in the application.

  • The interface must be able to keep track of the current element.
  • And should know how to move to the next element.

In short, the Iterator Design pattern presents a way to access the elements of an object without exposing the underlying presentation.

But, one can think of doing iteration using For or while loop, then why do we need iterator Pattern?

Why Iterator Design Pattern?

  • In Python, there is no concept of public, private and protected members inside a class.
  • So the part of the definition saying ‘without exposing its internal representation’ becomes somewhat futile.
  • Having said that, the Iterator Pattern aims at providing the client with a standard interface, hiding the under lying implementation.

Whereas, For and While loop tends to tightly couple the entities as iteration using loops uses the length of the iterable.

Implementation

Let us create an application that will iterate through the menu card of a restaurant.

  • Class to create Food item objects.
class FoodItem:
    def __init__(self, name, price):
        self.name = name
        self.price = price

    def __str__(self):
        return f"{self.name :<6}: $ {self.price}"
  • Menu class, having methods to add and remove Food objects.
class Menu:
    def __init__(self):
        self.items = []

    def add(self, item):
        self.items.append(item)
    
    def remove(self):
        return self.items.pop()

    def iterator(self):
        return MenuIterator(self.items)
  • Then our iterator interface(class), having custom iter and next method.
class MenuIterator:
    def __init__(self, items):
        self.indx = 0
        self.items = items

    def has_next(self):
        return False if self.indx >= len(self.items) else True

    def next(self):
        item = self.items[self.indx]
        self.indx += 1
        return item
  • The driver code.
if __name__ == '__main__':
    i1 = FoodItem("Burger", 7)
    i2 = FoodItem("Pizza", 8)
    i3 = FoodItem("Coke", 5)

    menu = Menu()
    menu.add(i1)
    menu.add(i2)
    menu.add(i3)

    print("Displaying Menu:")
    iterator = menu.iterator()
    while iterator.has_next():
        item = iterator.next()
        print(item)
Output:
Displaying Menu:
Burger: $ 7
Pizza : $ 8
Coke  : $ 5

Pros and Cons of Iterator Design Pattern

Pros

  • Facilitates to create custom traversal mechanism.

Cons

  • Iterator interface may tend to overuse the available resources.
  • Addition of iterator interface may increase the complexityof the code