[Python-Dev] Re: PEP 279

jepler@unpythonic.dhs.org jepler@unpythonic.dhs.org
Sat, 30 Mar 2002 08:56:19 -0600


On Sat, Mar 30, 2002 at 08:55:24AM -0500, Raymond Hettinger wrote:
> Hmm, the client code needs to maintain TWO instance variables, the generator
> object and the instance of Whatever.  It works but doesn't smell right to
> me:
> 
> w = Whatever()
> wg = w.generator()
> wg.next()
> wg.next()
> w.stop(); wg.next()    # trigger clean-up

I think this example can be embellished a bit to avoid this problem.
HaltingIterator subclasses define the .generator() method, but instantiates
it in the __init__ method, calling it at the right time from the .next()
method.  Cleanup is moved into a separate method, called from .stop() with
an optional argument.  Calling stop also makes the next .next() call raise
StopIteration (unless you happen to call .stop() with a false argument, though).

I had a bit of confusion that there's not StopIteration traceback printed,
and neither is "after that".  Apparently an uncaught StopIteration call
just exits silently?  (I'm using 2.3a0 here, in the case that it
matters---cvs from 2-3 weeks ago)

Jeff Epler


from __future__ import generators

class HaltingIterator:
    def __init__(self, *args, **kw):
	self._stop = 0
	self._generator = self.generator(*args, **kw)

    def stop(self, arg=1):
	self._stop = arg
	self.cleanup(arg)

    def next(self):
	if self._stop:
	    raise StopIteration
	return self._generator.next()

    def cleanup(self, arg): pass


class ExampleHaltingIterator(HaltingIterator):
    def generator(self):
	a, b = 1, 1
	while 1:
	    ret = a
	    ret, a, b = a, b, a+b
	    yield ret

    def cleanup(self, arg):
	print "halted with", arg

x = ExampleHaltingIterator()

for i in range(10): print x.next()
x.stop("76 trombones")
print x.next()
print "after that"