reseting an iterator

Duncan Booth duncan.booth at invalid.invalid
Thu May 21 10:46:38 CEST 2009

Steven D'Aprano <steven at> wrote:

> On Wed, 20 May 2009 11:35:47 -0700, Jan wrote:
>> Wouldn't it be easy for Python to implement generating functions so that
>> the iterators they return are equipped with a __reset__() method?
> No.
> def gen():
>     for name in os.listdir('.'):
>         yield open(name).read()
>         os.remove(name)
> How would you "easily" reset this generator so that it returns the same 
> values each time?
> That's an extreme example, but as a general rule, generators/iterators 
> are one-shot: having consumed a value, you can't get it back again 
> without re-creating it from scratch, or possibly not even then. Here's a 
> less destructive example:
> def gen():
>     for i in xrange(10):
>         yield time.time()

While I agree 100% with your 'No', I don't actually agree with your 

Why are you assuming that resetting a generator should return the same 
values each time? Why shouldn't resetting put it back to some known state, 
but allow the resulting output to vary?

For example, that's what happens in the .Net universe with Linq: a Linq 
expression is roughly equivalent to a Python iterable and every time you 
iterate over it you can get a different set of results.

The following code would, I think, work except that generators don't allow 
you to add attributes:

from functools import wraps
def resettable(generator):
	def wrapper(*args, **kw):
		def __reset__():
		    gen = generator(*args, **kw)
		    gen.__reset__ = __reset__
		    return gen
		return __reset__()
	return wrapper

def gen(n):
	for i in xrange(n):
		yield i, time.time()

import time
it = gen(3)
for v in it: print v
it = it.__reset__()
for v in it: print v

The simpler solution is just to reconstruct the iterator yourself.

Duncan Booth

More information about the Python-list mailing list