22

So I have a generator function, that looks like this.

def generator():
    while True:
        for x in range(3):
            for j in range(5):
                yield x

After I load up this function and call "next" a bunch of times, I'd expect it to yield values

0 0 0 0 0 1 1 1 1 1 2 2 2 2 2 0 0 0 0 0 ...

But instead it just yields 0 all the time. Why is that?

>>> execfile("test.py")
>>> generator
<function generator at 0x10b6121b8>
>>> generator().next()
0
>>> generator().next()
0
>>> generator().next()
0
>>> generator().next()
0
>>> generator().next()
0
>>> generator().next()
0
>>> generator().next()
0
2
  • 25
    I fail to see why this is so special. If you'd reinstantiate some class, no one would be surprised when some kind of initial value does not get updated! E.g. loading in a file 10 times and doing next() and print would certainly not be so spectacular to need 14 upvotes and 2 favorites... Commented Apr 10, 2015 at 21:57
  • 4
    Short answer, each generator() call returns a new generator object which starts at its beginning. Try gen = generator(), then gen.next(), gen.next(), etc. Commented Apr 11, 2015 at 17:39

3 Answers 3

48

generator() initializes new generator object:

In [4]: generator() is generator() # Creating 2 separate objects
Out[4]: False

Then generator().next() gets the first value from the newly created generator object (0 in your case).

You should call generator once:

In [5]: gen = generator() # Storing new generator object, will reuse it

In [6]: [gen.next() for _ in range(6)] # Get first 6 values for demonstration purposes
Out[6]: [0, 0, 0, 0, 0, 1]

Note: generator.next was removed from Python 3 (PEP 3114) - use the next function instead:

In [7]: next(gen)
Out[7]: 1
Sign up to request clarification or add additional context in comments.

1 Comment

.. but generator.__next__ was added. Still, you should use the next() function anyway.
17

With each call of generator you are creating a new generator object:

generator().next() # 1st item in 1st generator 
generator().next() # 1st item in 2nd generator

Create one generator, and then call the next for subsequent items:

g = generator()

g.next() # 1st item in 1st generator
g.next() # 2nd item in 1st generator

1 Comment

A new generator object, surely?
2

I posted it in the comment, I think if you look at this in parallel with the question you see the mistake:

with open('my_file.txt', 'r') as f: 
    print(f.readline())               # `readline` simply reads a single line

with open('my_file.txt', 'r') as f: 
    print(f.readline())

with open('my_file.txt', 'r') as f: 
    print(f.readline())

with open('my_file.txt', 'r') as f: 
    print(f.readline())    

Instead of making a new generator object each time, you have to make it once and then use it until it has been depleted:

mygen = generator()
mygen.next()
mygen.next()
...
etc

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.