-1

Once I use a generator once, it can't be used again. Why is this?

Consider the following code:

def generator(n):
  a = 1

  for _ in range(n):
    yield a
    a += 1

def run_generator(generator):
  for a in generator:
    print(a, end = " ")

If I were to execute this:

count_generator = generator(10)
run_generator(count_generator)
run_generator(count_generator)

It would only print:

1 2 3 4 5 6 7 8 9 10

Basically, the generator just dies after a single execution.

I know that the fact that a generator can only be used once is something built into Python, but why is it like this? Is there a specific reason to only allowing a generator object to be executed once?

Frank
  • 414
  • 4
  • 15
  • 1
    Because generators are not designed to be used again. That has many advantages, the primary one being memory efficiency, but not every iterable process can just be restarted. Instead, it is up to the programmer to re-create the same generator if they know it is safe to re-run that process. – Martijn Pieters Jun 25 '18 at 21:49
  • 2
    Thanks for the reply. That was what I was looking for. Not sure why my post got so many downvotes; I guess Stack Overflow is just living up to its reputation of pushing away new users. :( – Frank Jun 25 '18 at 22:31
  • 1
    This question is not related to the question it allegedly duplicates. This question doesn't ask how a generator works, it asks *why a generator can only be used once*. Although @MartijnPieters says, "Because side-effects", I would appreciate a more in-depth reason/answer. – JS. Apr 14 '22 at 23:20
  • @JS. how would you imagine reusing a generator would work when the resources that the generator based the output on *are no longer there*? Anything involving `random` would also no longer be re-creatable, etc. Generators generate, they don't retain. – Martijn Pieters Apr 15 '22 at 09:53
  • I would expect it would work the same as when I instantiate a generator in the first place. I clearly don't have an in-depth knowledge of the internals of generators and why re-using is impractical vs re-creating. That's why I am asking (voting to re-open) the question. Semi-snarky questions don't help me to understand. – JS. Apr 15 '22 at 22:38
  • 1
    itertools.cycle provides a reusable generator, see this answer https://stackoverflow.com/questions/23416381/circular-list-iterator-in-python – Jay M Apr 22 '22 at 16:15

1 Answers1

5

A generator works like ticker tape. When you call next on it, it gives you the next number, but then it forgets it, unlike a list. This is where most of the efficiency comes from. Since it doesn't have to remember what its previous values were, there's a much smaller memory footprint (especially when not all of its values will eventually be needed!)

Some generators can perhaps be reset to be able to run again, but that's by no means guaranteed, and some generators will outright fail if you try to do that. Python is not a pure language, and so you might have generators that modify state while they produce values. For instance, a generator such as:

def gimme_randoms():
    while True:
        yield random.random()

I can call this a bunch, but the state behind the PRNG in random will change every time I do.

rs = gimme_randoms()
a = next(rs)
b = next(rs)
c = next(rs)  # some numbers

What would it mean to reset this state? Well you'd expect:

rs2 = gimme_randoms()
x = next(rs2)
y = next(rs2)
z = next(rs2)

assert a == x and b == y and c == z  # Nonsense!

To make this hold, well, you'd have to keep track of the initial state of the PRNG, then have a way to set its seed back to the initial state. That's certainly doable, but it's not the generator's job to know how its underlying implementation has modified state.

Adam Smith
  • 52,157
  • 12
  • 73
  • 112
  • Ah, I see. So basically a generator is a more memory efficient list (if I'm understanding correctly). – Frank Jun 25 '18 at 22:30
  • @Frank I wouldn't characterize it that way, but I suppose in a minimal sense yes. It is a (possibly infinite) ordered collection of data that can only be gone through once. – Adam Smith Jun 25 '18 at 22:35