# How to reinitialize a generator.

Hi,

I would like to know how to reinitialize/reset a generator. I mean, if I for example have:

sage: generator = (n for n in range(1,10000) if (is_prime(n) & is_prime(n+2)))


And then i run generator.next() for example twice. How can i reinitialize/rest this generator so that when i run generator.next() again i get the first element?

If it is possible, i would thank you a lot if you can link the documentation file with the info, because i have searching for it so long and I didn't find anything.

Thanks ;)

P.D. Maybe my english is not good enought and i misspelled some words. Sorry about that.

edit retag close merge delete

Sort by » oldest newest most voted

Thanks both of you for the answers.

I have been told there must be a way to reset a generator without re-declaring it, and i have to find it :S I have been for long time on the doc searching, but I either found the way to reset it, or that there is no way to do that.

Could you link me from the documentation where it is said that you cannot reset a generator? (or how to, if it is actually possible)

more

"I have been told there must be a way to reset a generator without re-declaring it[.]" Perhaps you should ask whoever told you there must be a way what exactly that way is, and if they can't tell you, you might wonder how they're so sure. :^)

( 2011-01-02 23:39:34 +0200 )edit

I'm not sure what you'll accept as evidence. You could read up on the generator protocol: http://docs.python.org/reference/expressions.html, or (maybe simpler) the functional programming tutorial (http://docs.python.org/howto/functional.html ): "Note that you can only go forward in an iterator; theres no way to get the previous element, reset the iterator, or make a copy of it. Iterator objects can optionally provide these additional capabilities, but the iterator protocol only specifies the next() method." You can trivially write something you *can* reset, if for some reason you like g.reset() more than g=gen(), but from a standard genexp it won't work. [Actually I can think of some low-level tricks which could probably pull off a reset but they're a terrible idea.]

( 2011-01-02 23:58:10 +0200 )edit

It was my math teacher the one who told me that. I have to figure out how to do that, cause that's +2 points for my SAGE exam :-P

( 2011-01-03 08:22:44 +0200 )edit

Really?! Maybe after the exam you or your teacher could explain it to us too! (p.s. is this website part of the allowed materials for the exam?)

( 2011-01-04 08:56:25 +0200 )edit

First one point: in general you probably don't want to use "range" in a generator expression because that actually builds the list, and avoiding list construction is one of the reasons people use generators and iterators in the first place. You often have to have a pretty sizable array to notice the difference, I admit:


----------------------------------------------------------------------
| Sage Version 4.6, Release Date: 2010-10-30                         |
| Type notebook() for the GUI, and license() for information.        |
----------------------------------------------------------------------
sage: w = 10**7
sage: time gen = (n for n in xrange(1,w) if (is_prime(n) & is_prime(n+2)))
CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
Wall time: 0.00 s
sage: time gen = (n for n in IntegerRange(1,w) if (is_prime(n) & is_prime(n+2)))
CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
Wall time: 0.00 s
sage: time gen = (n for n in range(1,w) if (is_prime(n) & is_prime(n+2)))
CPU times: user 0.19 s, sys: 0.25 s, total: 0.44 s
Wall time: 0.44 s


Note that there are int construction overheads the first time, and for small range size (for some definition of small) the difference won't matter -- range might even be faster -- but it's still going through the loop, so it'll break for really big sizes even if you only ever look at a few values. Try w=10**9 and prepare to wait..

As for your real question, I don't know of a good way to clone a generator expression using the standard tools. (A ".restart()" method wouldn't make any sense in many cases, which is one of the reasons it's not part of the protocol.) You can use itertools.tee to make multiple cached copies of the output, but since it's caching the values to do the trick you could have memory problems or accuracy problems if the function is nondeterministic.

But if you want to reinitialize the generator and start over, why not simply redeclare it instead? If you dislike the code duplication, you could wrap it in a function:


sage: def twin_prime_gen(upto=10**4):
....:         return (n for n in xrange(1,upto+1) if (is_prime(n) & is_prime(n+2)))
....:
sage: a = twin_prime_gen()
sage: next(a)
3
sage: next(a)
5
sage: a = twin_prime_gen()  # instead of a.restart(), which doesn't exist
sage: next(a)
3


which I think should have mostly the same effect.

[UPDATE: Oops, didn't update my window, so didn't see Niles already said the same thing!]

more

Hi Tlk!

Generators come from python, and I found a similar question at stackoverflow:

http://stackoverflow.com/questions/12...

The basic answer seems to be that generators can't be reset. Instead, you could re-run the code which creates the generator to make a fresh copy of it, or you could store the outputs of the generator in a list so that you can reuse them. If neither of these will work, you could perhaps modify how the generator is built so that re-creating it does not take too long (for example, do computationally intense parts first, store the output, and use that to create the generator).

UPDATE: For the particular example you gave, it's easy enough to just recreate the generator:

sage: generator = (n for n in range(1,10000) if (is_prime(n) & is_prime(n+2)))
sage: generator.next()
3
sage: generator.next()
5
sage: generator.next()
11
sage: generator = (n for n in range(1,10000) if (is_prime(n) & is_prime(n+2)))
sage: generator.next()
3
sage: generator.next()
5


Feel free to post more details about your particular problem if you want :)

good luck! Niles

more