2016-09-21 42 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) 
相關問題