Restart generator when it is exhausted.

L

Lacrima

Hello!

I am quite new to Python and I have maybe simple (or maybe not)
question.

Is it possible to restart generator when it is exhausted?
For example:
a = ['a', 'b', 'c']
g = (i for i in a)
g.next() 'a'
g.next() 'b'
g.next() 'c'
g.next()
Traceback (most recent call last):
File "<pyshell#31>", line 1, in <module>
g.next()
StopIterationWhat should I do to get the initial state of g? So if I do again g.next
() I receive 'a'.

If it is not possible what are common techniques to use iterator or
generator objects that allow restarting when it is needed?

With regards,
Max

(sorry if my English isn't very proper)
 
C

Chris Rebert

Hello!

I am quite new to Python and I have maybe simple (or maybe not)
question.

Is it possible to restart generator when it is exhausted?

No. You have to make a new instance of the generator.
What should I do to get the initial state of g? So if I do again g.next
() I receive 'a'.

g = (i for i in a) #that is, make a fresh generator instance
If it is not possible what are common techniques to use iterator or
generator objects that allow restarting when it is needed?

There's itertools.cycle() --
http://docs.python.org/library/itertools.html#itertools.cycle

Cheers,
Chris
 
L

Lacrima

No. You have to make a new instance of the generator.


g = (i for i in a) #that is, make a fresh generator instance


There's itertools.cycle() --http://docs.python.org/library/itertools.html#itertools.cycle

Cheers,
Chris
--http://blog.rebertia.com

Chris, thanks a lot for the help!
 
J

J. Cliff Dyer

Lacrima said:
If it is not possible what are common techniques to use iterator or
generator objects that allow restarting when it is needed?

The usual thing if you want to use the generator's output more than once
would be to convert the generator to a list, then you can iterate over it
as often as you want.
a = ['a', 'b', 'c']
g = (i for i in a)
restartable = list(g)

If you want the output of the generator to potentially change each time you
iterate then you need to create a new generator.

More verbosely, but without putting your generator in , you can use the
iterator protocol to create a reusable iterable:

An iterable is a class with an __iter__ method that returns an iterator.

So for example:

class Iterator(object):
def __init__(self, filename):
self.f = open(filename)

def __iter__(self):
return self

def next(self):
line = self.f.readline()
if not line:
raise StopIteration
return line.strip()[:8]

is an iterator (which is also an iterable), which will grab each line of
a file, returning the first eight non-whitespace characters until the
file is used up. Then the iterator is exhausted, and will continue to
raise StopIteration each time it is called.

class Iterable(object):
def __init__(self, filename):
self.filename = filename

def __iter__(self):
return Iterator(self.filename)

This is a reusable iterable which returns a new instance of the Iterator
class above each time it is exhausted.

So given a file hello.txt:

Hello world
Hola mundo
Guten tag, weld.

The classes can be used as followed:*** 0 ***
Hello wo
Hola mun
Guten ta
*** 1 ***
*** 2 ****** 0 ***
Hello wo
Hola mun
Guten ta
*** 1 ***
Hello wo
Hola mun
Guten ta
*** 2 ***
Hello wo
Hola mun
Guten ta

When Iterator hits a StopIteration, it passes out of the inner loop, and
when it comes back in, the inner loop calls iterator.__iter__(), and
gets the same exhausted iterator (which immediately breaks the inner
loop by raising StopIteration). In Iterable, when the loop calls
iterable.__iter__(), it gets a fresh iterator, so it can loop over the
file again.

The important thing is that when you call x.__iter__() (which you do
when entering a loop), you get a fresh iterator that won't just call
StopIteration right away.

Cheers,
Cliff
 
L

Lacrima

The usual thing if you want to use the generator's output more than once  
would be to convert the generator to a list, then you can iterate over it
as often as you want.
a = ['a', 'b', 'c']
g = (i for i in a)
restartable = list(g)
If you want the output of the generator to potentially change each time you
iterate then you need to create a new generator.

More verbosely, but without putting your generator in , you can use the
iterator protocol to create a reusable iterable:

An iterable is a class with an __iter__ method that returns an iterator.

So for example:

class Iterator(object):
    def __init__(self, filename):
        self.f = open(filename)

    def __iter__(self):
        return self

    def next(self):
        line = self.f.readline()
        if not line:
            raise StopIteration
        return line.strip()[:8]

is an iterator (which is also an iterable), which will grab each line of
a file, returning the first eight non-whitespace characters until the
file is used up.  Then the iterator is exhausted, and will continue to
raise StopIteration each time it is called.

class Iterable(object):
    def __init__(self, filename):
        self.filename = filename

    def __iter__(self):
        return Iterator(self.filename)

This is a reusable iterable which returns a new instance of the Iterator
class above each time it is exhausted.

So given a file hello.txt:

  Hello world
    Hola mundo
  Guten tag, weld.

The classes can be used as followed:>>> iterator = Iterator('hello.txt')
*** 0 ***
Hello wo
Hola mun
Guten ta
*** 1 ***
*** 2 ***>>> iterable = Iterable('hello.txt')
*** 0 ***
Hello wo
Hola mun
Guten ta
*** 1 ***
Hello wo
Hola mun
Guten ta
*** 2 ***
Hello wo
Hola mun
Guten ta

When Iterator hits a StopIteration, it passes out of the inner loop, and
when it comes back in, the inner loop calls iterator.__iter__(), and
gets the same exhausted iterator (which immediately breaks the inner
loop by raising StopIteration).  In Iterable, when the loop calls
iterable.__iter__(), it gets a fresh iterator, so it can loop over the
file again.

The important thing is that when you call x.__iter__() (which you do
when entering a loop), you get a fresh iterator that won't just call
StopIteration right away.

Cheers,
Cliff

Thank you very much! You completely have enlightened me on all my
questions!

-Max
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,994
Messages
2,570,223
Members
46,813
Latest member
lawrwtwinkle111

Latest Threads

Top