revive a generator

Chris Angelico rosuav at gmail.com
Fri Oct 21 04:27:40 EDT 2011


On Fri, Oct 21, 2011 at 7:02 PM, Yingjie Lan <lanyjie at yahoo.com> wrote:
> What if the generator involves a variable from another scope,
> and before re-generating, the variable changed its value.
> Also, the generator could be passed in as an argument,
> so that we don't know its exact expression.
>

There's actually no way to know that the generator's even
deterministic. Try this, for instance:

>>> g=(input("Enter value %d or blank to stop: "%n) for n in range(1,11))
>>> for s in g:
	if not s: break
	print("Processing input: "+s)

It may not be particularly useful, but it's certainly legal. And this
generator cannot viably be restarted. The only way is to cast it to
list first, but that doesn't work when you have to stop reading
expressions from the generator part way.

What you could perhaps do is wrap the generator in something that
saves its values:

>>> class restartable(object):
	def __init__(self,gen):
		self.gen=gen
		self.yielded=[]
		self.iter=iter(self.yielded)
	def restart(self):
		self.iter=iter(self.yielded)
	def __iter__(self):
		return self
	def __next__(self): # Remove the underscores for Python 2
		try:
			return self.iter.__next__()
		except StopIteration:
			pass
		ret=self.gen.__next__()
		self.yielded.append(ret)
		return ret

>>> h=restartable(g)
>>> for i in h:
	if not i: break
	print("Using: ",i)
>>> h.restart()
>>> for i in h:
	if not i: break
	print("Using: ",i)

Complicated, but what this does is returns a value from its saved list
if there is one, otherwise returns a value from the original
generator. It can be restarted as many times as necessary, and any
time you read "past the end" of where you've read so far, the original
generator will be called upon.

Actually, this model might be useful for a repeatable random-number
generator. But those are more efficiently restarted by means of
reseeding the PRNG.

ChrisA



More information about the Python-list mailing list