Iterators

What Is an Iterator?

  • An iterator is an object that contains a countable number of values and can be iterated upon, meaning you can traverse through all the values.

Iterator vs. Iterable:

  • Lists, tuples, dictionaries, and sets are iterable objects. You can get an iterator from them using the iter() method.
  • Example: Returning an iterator from a tuple:

    python
    mytuple = ("apple", "banana", "cherry")
    myit = iter(mytuple)
    print(next(myit))  # Output: apple
    print(next(myit))  # Output: banana
    print(next(myit))  # Output: cherry
    
  • Strings are also iterable objects:

    python
    mystr = "banana"
    myit = iter(mystr)
    print(next(myit))  # Output: b
    print(next(myit))  # Output: a
    print(next(myit))  # Output: n
    

Looping Through an Iterator:

  • You can use a for loop to iterate through an iterable object:

    python
    mytuple = ("apple", "banana", "cherry")
    for x in mytuple:
        print(x)
    
  • The for loop creates an iterator object and executes the next() method for each loop.

Creating an Iterator:

  • To create an object/class as an iterator, implement the __iter__() and __next__() methods.
  • Example: Creating an iterator that returns numbers starting with 1:

    python
    class MyNumbers:
        def __iter__(self):
            self.a = 1
            return self
        def __next__(self):
            x = self.a
            self.a += 1
            return x
    myclass = MyNumbers()
    myiter = iter(myclass)
    print(next(myiter))  # Output: 1
    print(next(myiter))  # Output: 2
    print(next(myiter))  # Output: 3
    

StopIteration:

  • To prevent infinite iteration, use the StopIteration statement in the __next__() method.
  • Example: Stopping after 20 iterations:

    python
    class MyNumbers:
        def __iter__(self):
            self.a = 1
            return self
        def __next__(self):
            if self.a <= 20:
                x = self.a
                self.a += 1
                return x
            else:
                raise StopIteration
    myclass = MyNumbers()
    myiter = iter(myclass)
    for x in myiter:
        print(x)
    

Exercises:

  1. Create an Iterator:
    • Create an iterator that returns the square of each number from 1 to 10.
    • Solution:

      python
      class SquareNumbers:
          def __iter__(self):
              self.a = 1
              return self
          def __next__(self):
              if self.a <= 10:
                  x = self.a ** 2
                  self.a += 1
                  return x
              else:
                  raise StopIteration
      squares = SquareNumbers()
      squares_iter = iter(squares)
      for num in squares_iter:
          print(num)
      
  2. Custom String Iterator:
    • Create an iterator that returns each character of a string in uppercase.
    • Solution:

      python
      class UpperString:
          def __init__(self, string):
              self.string = string
              self.index = 0
          def __iter__(self):
              return self
          def __next__(self):
              if self.index < len(self.string):
                  char = self.string[self.index].upper()
                  self.index += 1
                  return char
              else:
                  raise StopIteration
      my_string = UpperString("hello")
      string_iter = iter(my_string)
      for char in string_iter:
          print(char)
      

Summary:

  • Iterators are essential for traversing through collections of data in Python. Understanding how to create and use iterators will help you manage sequences and loops more effectively. Practice creating custom iterators to master this concept