Can generator be used more than once?
Asked Answered
P

5

17

This is my piece of code with two generators defined:

one_line_gen = (x for x in range(3))

def three_line_gen():
    yield 0
    yield 1
    yield 2

When I execute:

for x in one_line_gen:
    print x

for x in one_line_gen:
    print x

The result is as expected:

0
1
2

However, if I execute:

for x in three_line_gen():
    print x

for x in three_line_gen():
    print x

The result is:

0
1
2
0
1
2

Why? I thought any generator can be used only once.

Pouched answered 30/7, 2017 at 12:51 Comment(3)
Don't confuse a generator function with the generator it produces.Sonstrom
Put differently, if you used def one_line_gen(): return (x for x in range(3)), your first example would be equivalent (producing a generator every time you called the function).Sonstrom
Closely related: Generator Expression vs yield: Why isn't 'next()' working?Sonstrom
L
16

three_line_gen is not a generator, it's a function. What it returns when you call it is a generator, a brand new one each time you call it. Each time you put parenthesis like this:

three_line_gen()

It is a brand new generator to be iterated on. If however you were to first do

mygen = three_line_gen()

and iterate over mygen twice, the second time will fail as you expect.

Latimer answered 30/7, 2017 at 12:57 Comment(0)
N
8

no, you can not iterate over a generator twice. a generator is exhausted once you have iterated over it. you may make a copy of a generator with tee though:

from itertools import tee

one_line_gen = (x for x in range(3))
gen1, gen2 = tee(one_line_gen)
# or: 
# gen1, gen2 = tee(x for x in range(3))

for item in gen1:
    print(item)

for item in gen2:
    print(item)

for the other issues see Ofer Sadan's answer.

Nada answered 30/7, 2017 at 12:59 Comment(0)
P
2

Why? I thought any generator can be used only once.

Because every call to three_line_gen() creates a new generator.

Otherwise, you're correct that generators only run forward until exhausted.

Can generator be used more than once?

Yes, it is possible if the results are buffered outside the generator. One easy way is to use itertools.tee():

>>> from itertools import tee
>>> def three_line_gen():
        yield 0
        yield 1
        yield 2

>>> t1, t2 = tee(three_line_gen())
>>> next(t1)
0
>>> next(t2)
0
>>> list(t1)
[1, 2]
>>> list(t2)
[1, 2]
Peyter answered 26/8, 2017 at 1:16 Comment(0)
D
1

Yes, generator can be used only once. but you have two generator object.

# Python 3


def three_line_gen():
    yield 0
    yield 1
    yield 2

iterator = three_line_gen()
print(iterator)
for x in iterator:
    print(id(iterator), x)

iterator2 = three_line_gen()
print(iterator2)
for x in iterator2:
    print(id(iterator2), x)

And the result is:

<generator object three_line_gen at 0x1020401b0>
4328784304 0
4328784304 1
4328784304 2
<generator object three_line_gen at 0x1020401f8>
4328784376 0
4328784376 1
4328784376 2
Ditheism answered 30/7, 2017 at 13:6 Comment(0)
C
0

Because in One liner is Generator Object while the three liner is a function. They meant to be different.

These two are similar.

def three_line_gen_fun():
    yield 0
    yield 1
    yield 2

three_line_gen = three_line_gen_fun()
one_line_gen = (x for x in range(3))

type(three_line_gen) == type(one_line_gen)
Chuu answered 30/7, 2017 at 12:58 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.