[Edu-sig] Another Iterator Example (2.2a)

Kirby Urner pdx4d@teleport.com
Mon, 23 Jul 2001 09:40:19 -0700


In the example below, we approximate the 2nd root of
a number using Newton's method.  Each call to the
.next() method of our generator function gives a next
approximation, until the next guess is no different
from the last one, at which point we return (warning:
this is *not* a good test on which to stop iteration,
as the guesses may oscillate between two values --
better is to stop when the difference is under some
threshold).

To return from a generator is to end its effective life
span, although it sticks around to remind you it's dead.
Further calls to it throw a StopIteration exception:

   >>> from play import *
   >>> s = sqrt(2)
   >>> s.next()
   1.0
   >>> s.next()
   1.5
   >>> s.next()
   1.4166666666666667
   >>> s.next()
   1.4142156862745099
   >>> s.next()
   1.4142135623746899
   >>> s.next()
   1.4142135623730949
   >>> s.next()
   Traceback (most recent call last):
   File "<pyshell#32>", line 1, in ?
     s.next()
   StopIteration

On the other hand, as we learned about iterators in general
in the last example, the for-loop use simply ends, without
throwing an exception, when the terminal condition is reached
(in this case, a return).

   >>> s = sqrt(2)
   >>> for i in s:  print "%r" % i

   1.0
   1.5
   1.4166666666666667
   1.4142156862745099
   1.4142135623746899
   1.4142135623730949

You can restart the generator simply by reinitializing it:

   >>> s = sqrt(2)
   >>> [i for i in s]
   [1.0, 1.5, 1.4166666666666667, 1.4142156862745099,
   1.4142135623746899, 1.4142135623730949]

Source:

from __future__ import generators

def sqrt(target):
     guess = 1.0  # initialize to 1
     while 1:
        newguess = (guess**2 + target)/(2*guess)
        yield guess
        if newguess==guess:
            return
        guess = newguess