-3

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
  • 346
  • 1
  • 12
  • 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
  • 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 Answers1

0

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
  • 45,072
  • 8
  • 62
  • 94
  • 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