[Edu-sig] Some design patterns with iterators

Kirby Urner urnerk@qwest.net
Wed, 02 Apr 2003 17:22:11 -0800


So, based on the foregoing, I'm playing around with the Seq class
below as a kind of template iterator.  It's designed to accept a
passed-in test, or to let the user override the default test method
-- or to not supply a test at all.

The idea is:  you want to generate this sequence, based on some rule.
By subclassing Seq, you inherit the iterator qualities you need, so
you can just focus on the __init__ and update methods, which define
the variables you'll be using, the the rule for going from one term
to the next in sequence (hence the name Seq).

The other wrinkle is the reset() method, which restores the iterator
to its initial state.  I'm not sure if this is a good idea, but it
seems like it might be useful.

Example use:

  >>> def t(self): return self.t1>1000

  >>> fibs = iters.Fibseq(0,1,t)

  >>> for i in fibs: print i,

  1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597

  >>> fibs.reset()
  >>> fibs.next()
  1



#---------- iters.py
from __future__ import division

class Seq(object):
     """
     Subclass and override update() to do the next iteration and
     to return a next value.

     Your subclass's __init__ should define whatever instance
     variables you need, including one named 'test' if you want
     to pass in a test for the purpose of limiting iteration.
     Or you may choose to override test in the source code.

     Iteration stops when the passed in test returns True.

     The test function, if written externally, should have self
     as an argument, and refer to your instance variables as if
     in a class, e.g. as self.variable.
     """

     def next(self):
         if not self.__dict__.has_key("_savedict"):
             self._savedict = self.__dict__.copy()
         if self.test(self):
             raise StopIteration
         else:
             return self.update()

     def update(self):
         pass

     def test(self):
         return False

     def __iter__(self):
         return self

     def reset(self):
         if self.__dict__.has_key("_savedict"):
            self.__dict__ = self._savedict.copy()

class Fibseq(Seq):
     """
     Demonstrates how to subclass Seq.  In this case, a test will
     be supplied upon initialization.  The user need define only
     __init__ and update.
     """

     def __init__(self,t1,t2,test):
         self.t1 = t1
         self.t2 = t2
         self.test = test

     def update(self):
         self.t1, self.t2 = self.t2, self.t1 + self.t2
         return self.t1