Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why exhausted generators raise StopIteration more than once?

Why is it that when an exhausted generator is called several times, StopIteration is raised every time, rather than just on the first attempt? Aren't subsequent calls meaningless, and indicate a likely bug in the caller's code?

def gen_func():
    yield 1
    yield 2
gen = gen_func()
next(gen)
next(gen)
next(gen) # StopIteration as expected
next(gen) # why StopIteration and not something to warn me that I'm doing something wrong

This also results in this behavior when someone accidentally uses an expired generator:

def do_work(gen):
    for x in gen:
        # do stuff with x
        pass

    # here I forgot that I already used up gen
    # so the loop does nothing without raising any exception or warning
    for x in gen:
        # do stuff with x
        pass

def gen_func():
    yield 1
    yield 2

gen = gen_func()
do_work(gen)

If second and later attempts to call an exhausted generator raised a different exception, it would have been easier to catch this type of bugs.

Perhaps there's an important use case for calling exhausted generators multiple times and getting StopIteration?

like image 548
max Avatar asked Sep 21 '16 16:09

max


1 Answers

Perhaps there's an important use case for calling exhausted generators multiple times and getting StopIteration?

There is, specifically, when you want to perform multiple loops on the same iterator. Here's an example from the itertools docs that relies on this behavior:

def grouper(iterable, n, fillvalue=None):
    "Collect data into fixed-length chunks or blocks"
    # grouper('ABCDEFG', 3, 'x') --> ABC DEF Gxx"
    args = [iter(iterable)] * n
    return zip_longest(*args, fillvalue=fillvalue)
like image 111
user2357112 supports Monica Avatar answered Sep 28 '22 20:09

user2357112 supports Monica