Page 1 of 1

Iterators in Python Part 2

#1 Simown  Icon User is offline

  • Blue Sprat
  • member icon

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

Posted 07 February 2011 - 02:28 PM

Iterators in Python Part 2

This tutorial will expand on my last tutorial: Here

I will show you how sequences such as lists and dictionaries can be converted into iterators, how iterators can be used to model a sequence and explain the benefit of using iterators.

How sequences can be converted to iterators:

>>> mylist = [1, 2, 3]
>>> mylist
[1, 2, 3]
iterator = iter(mylist)
>>> iterator
<listiterator object at 0x031CB650>



As you can see the iter() function converts a list (or any sequence) into an iterator object, which can be used as follows:

>>> iterator = iter([1, 2, 3])
>>> iterator.next()
1
>>> iterator.next()
2
>>> iterator.next()
3
>>> iterator.next()
Traceback (most recent call last):
  File "<interactive input>", line 1, in <module>
StopIteration



The next() method displays the next value in the sequence, if there are no more values it raises a StopIteration exception, these are covered in more detail in the previous tutorial.

A few more examples with different sequences:

>>> tup = (5, 4, 3)
>>> iterator = iter(tup)
>>> iterator
<tupleiterator object at 0x031CBFB0>
>>> iterator.next()
5
>>> iterator.next()
4
>>> iterator.next()
3
>>> iterator.next()
Traceback (most recent call last):
  File "<interactive input>", line 1, in <module>
StopIteration

>>> dict = {1:"one", 2:"two", 3:"three"}
>>> iterator = iter(dict)
>>> iterator
<dictionary-keyiterator object at 0x031D0F60>
>>> iterator.next()
1
>>> iterator.next()
2
>>> iterator.next()
3
>>> iterator.next()
Traceback (most recent call last):
  File "<interactive input>", line 1, in <module>
StopIteration


Every object has it's own type of iterator, list has a listiterator, a tuple has a tupleiterator, a dictionary by default will produce a dictonary-keyiterator which will iterate through the keys of the dictionary rather than the key:value pairs.

Python 3:

The syntax has changed slightly for users using Python 3.x, objects using the iterator protocol have a method called __next__ rather than next but the values are accessed by a function called next()!

#Using Python 3.1

>>> mylist = ["a", "b", "c"]
>>> iterator = iter(mylist)
>>> next(iterator)
'a'
>>> next(iterator)
'b'
>>> next(iterator)
'c'



Why iterators?

Why not just use a list? Well, that might be excessive and a waste in some cases, for example, if you had a series of numbers say: the Fibonacci series and you just wanted a single value, with a list you'd have to generate all the proceeding values which would take up a lot of memory! Iterators make this simple.

I'll move away from the Fibonacci series now, it's probably used way too much in examples, now consider the sum of the first n numbers:

n = 4, 1 + 2 + 3 + 4 = 10

n = 10, 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 = 55

More generally:

n = n, 1 + 2 + ... (n - 1) + n

If you wanted the first value of n that produced a value over 1,000,000 you could accomplish this using a list sure, if you don't run out of memory first but it's inelegant and messy.

Sum of the first n numbers using an iterator:

class NaturalNumbers:
    def __init__(self):
        self.a = 0
        self.b = 0
    def next(self):
        self.a = self.a + 1
        self.b = self.b + self.a
        return self.b
    def n(self):
        return self.a
    def __iter__(self):
        return self

num = NaturalNumbers()
for x in num:
   if x > 1000000:
       print "The first number bigger than 1,000,000 is", x
       print "The sum of", num.n(), "numbers"
       break


...
The first number bigger than 1,000,000 is 1000405
The sum of 1414 numbers



This code should be fairly simple if you followed the last tutorial through:

class NaturalNumbers:
    def __init__(self):
        self.b = 0
        self.a = 0



The class I created is called NaturalNumbers, a will hold the value of n in the sequence and b will hold the sum of the first n numbers. These are both initially 0.
    def next(self):
        self.a = self.a + 1
        self.b = self.b + self.a
        return self.b



When next is called, a is incremented by 1, which is the next value of n to add to b.
b is returned which will correspond to the sum of the first n numbers up to that point. It's important to note that b is not printed during the execution.

    def n(self):
        return self.a
    def __iter__(self):
        return self



Calling the method will return the nth in the iteration (which corresponds to a) so that we can print the value.
The __iter__ method will return the iterator object (again, discussed in the last tutorial)

num = NaturalNumbers()



num is assigned to an instance of our sum-generating-iterator object, we can now use it directly in a for loop to find the smallest value of n that produces a sum > 1,000,000.

for x in num:
   if x > 1000000:
       print "The first number bigger than 1,000,000 is", x
       print "The sum of", num.n(), "numbers"
       break


Each number in the iterator is checked and when it exceeds 1,000,000, x is printed, to show the value of n, num.n() is called.

An infinite list:
The loops stops only because I have issued a break statement after the value has printed, otherwise, the for loop would never end and generate an infinite number of values as there is no StopIteration exception!!

Back to my first examples, demonstrating another use:

# n = 4,  1 + 2 + 3 + 4 = 10
class NaturalNumbers:
    def __init__(self):
        self.a = 0
        self.b = 0
    def next(self):
        self.a = self.a + 1
        self.b = self.b + self.a
        return self.b
    def n(self):
        return self.a
    def __iter__(self):
        return self


num = NaturalNumbers()
for x in num:
   if num.n() == 4:
       print "The sum of the first", num.n(), "numbers is:", x
       break
...
The sum of the first 4 numbers is: 10

# n = 10, 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10
num = NaturalNumbers()
for x in num:
   if num.n() == 10:
       print "The sum of the first", num.n(), "numbers is:", x
       break
...
The sum of the first 10 numbers is: 55

#n = 999999, 1 + 2 + 3 + 4 + 5 + ..... + 999998 + 9999999
num = NaturalNumbers()
for x in num:
   if num.n() == 999999:
       print "The sum of the first", num.n(), "numbers is:", x
       break

....
>>> The sum of the first 999999 numbers is: 499999500000



And that concludes my tutorials on iterators, I hope you can now see the benefits of using iterators rather than lists and how they can be used to provide a much neater solution.

Is This A Good Question/Topic? 1
  • +

Page 1 of 1