Page 1 of 1

Iterators in Python – Part 1

#1 Simown  Icon User is offline

  • Blue Sprat
  • member icon

Reputation: 319
  • View blog
  • Posts: 650
  • Joined: 20-May 10

Posted 03 February 2011 - 02:54 PM

Iterators in Python – Part 1

It’s not necessary just to iterate over lists in Python with a simple for loop, many things can be used as an iterable, dictionaries, sequences: all objects that implement the __iter__ method!

The __iter__ method in a class returns an iterator which requires the object in question to have a next() method, this method should generate the iterables next value if called and raise an exception if there is no more values.

The range(10) function lists all numbers between 0 and 10 (0, 1, 2, 3, 4, 5, 6, 7, 8, 9). I will implement this function as a class to demonstrate how an iterator can be used as a sequence:

class range2:
    def __init__(self, stop):
        self.stop = stop
        self.start = -1
    def next(self):
        self.start = self.start + 1
        if  self.start >= self.stop : raise StopIteration
        return self.start
    def __iter__(self):
        return self


It can be used like this:

>>> r = range2(10)
>>> print list(r)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]


It is important to note that the range2() class returns an iterator object and not a list, to print it out as a list you must explicitly convert it with the list() function.

Implementation

class range2:


I am not implementing a function such as range(), range2() is a class!

    def __init__(self, stop):
        self.stop = stop
        self.start = -1


This initialises the values of start to be -1 and stop to be the value entered as a parameter, it begins at -1 because 0 is printed first, if it was 0 the next value in the iterator would be 1 when it started and that's not what we want!

  def next(self):
        self.start = self.start + 1


Now the important bit for all iterators, they must have a next() method which will be called automatically to generate the "next" value of the iterator. As you can see here our value is increased by 1 each time next is called.


        if  self.start >= self.stop : raise StopIteration


If the iterator kept calling next() it would keep generating new values forever! To avoid this raise an exception raise StopIteration (specific to iterators) when the value of start is equal or greater than where it is meant to stop. Only values from 0 to n-1 should be generated.

return self.start


This is the value we want to show, the increasing value, we return it from the next() method.

    def __iter__(self):
        return self


Finally, the __iter__ method is implemented, which returns the iterator itself it can then be used directly in a for loop.

A few examples:

>>> range2(10)
<__main__.range2 instance at 0x030122B0>

>>> list(range2(10))
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

>>> list(range(5))
[0, 1, 2, 3, 4]

>>> for r in range2(5):	
          print r,	
0 1 2 3 4


Look out for a more complex implementation of range2() in the snippets section soon!

In part 2, I will implement an iterator as a list of infinite length and show you the benefit of using iterators rather than lists.

Is This A Good Question/Topic? 1
  • +

Page 1 of 1