2016-09-21 55 views
4

为什么当一个耗尽的发电机多次被调用时,每次都会产生StopIteration,而不仅仅是第一次尝试?以后的调用没有意义,并且在调用者的代码中指出可能的错误?为什么耗尽的发电机不止一次提升StopIteration?

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 

这也导致此行为,当有人不小心使用了过期的发电机:

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) 

如果第二次和以后尝试调用疲惫发生器提出了不同的异常,这本来是更容易捕捉这种类型的错误。

也许有一个重要的用例多次调用耗尽的发电机并获得StopIteration

+1

疲惫的发电机撑耗尽。 – Daniel

+0

如果您需要重复生成器生成的值,请将这些值加载到列表中,或创建生成器的新副本。 –

+0

在你的第二个例子中'for'显式处理'StopIteration',并且实际上变成了no-op。如果你尝试使用'next(gen)'而不是 - 你会得到另一个'StopIteration' ... –

回答

2

也许有一个重要的用例多次调用耗尽的发电机并获得StopIteration

有,特别是,当你想要在同一个迭代器上执行多个循环。下面是来自itertools文档依赖此行为的一个例子:

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)