Note that there are some explanatory texts on larger screens.

plurals
  1. POHow to make a repeating generator in Python
    text
    copied!<p>How do you make a repeating generator, like xrange, in Python? For instance, if I do:</p> <pre><code>&gt;&gt;&gt; m = xrange(5) &gt;&gt;&gt; print list(m) &gt;&gt;&gt; print list(m) </code></pre> <p>I get the same result both times — the numbers 0..4. However, if I try the same with yield:</p> <pre><code>&gt;&gt;&gt; def myxrange(n): ... i = 0 ... while i &lt; n: ... yield i ... i += 1 &gt;&gt;&gt; m = myxrange(5) &gt;&gt;&gt; print list(m) &gt;&gt;&gt; print list(m) </code></pre> <p>The second time I try to iterate over m, I get nothing back — an empty list.</p> <p>Is there a simple way to create a repeating generator like xrange with yield, or generator comprehensions? I found <a href="http://bugs.python.org/msg89898" rel="nofollow noreferrer">a workaround on a Python tracker issue</a>, which uses a decorator to transform a generator into an iterator. This restarts every time you start using it, even if you didn't use all the values last time through, just like xrange. I also came up with my own decorator, based on the same idea, which actually returns a generator, but one which can restart after throwing a StopIteration exception:</p> <pre><code>@decorator.decorator def eternal(genfunc, *args, **kwargs): class _iterable: iter = None def __iter__(self): return self def next(self, *nargs, **nkwargs): self.iter = self.iter or genfunc(*args, **kwargs): try: return self.iter.next(*nargs, **nkwargs) except StopIteration: self.iter = None raise return _iterable() </code></pre> <p>Is there a better way to solve the problem, using only yield and/or generator comprehensions? Or something built into Python? So I don't need to roll my own classes and decorators?</p> <h1>Update</h1> <p>The <a href="https://stackoverflow.com/questions/1376438/how-to-make-a-repeating-generator-in-python#comment1221812_1376531">comment by u0b34a0f6ae</a> nailed the source of my misunderstanding:</p> <blockquote> <p>xrange(5) does not return an iterator, it creates an xrange object. xrange objects can be iterated, just like dictionaries, more than once.</p> </blockquote> <p>My "eternal" function was barking up the wrong tree entirely, by acting like an iterator/generator (<code>__iter__</code> returns self) rather than like a collection/xrange (<code>__iter__</code> returns a new iterator).</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload