2015-07-11 77 views
4

這兩個代碼片段僅在列表構造方式上有所不同。一個使用[],另一個使用list()爲什麼這些生成器表達式的行爲有所不同?

這一次所消耗的迭代,然後提出了一個StopIteration

>>> try: 
...  iterable = iter(range(4)) 
...  while True: 
...   print([next(iterable) for _ in range(2)]) 
... except StopIteration: 
...  pass 
... 
[0, 1] 
[2, 3] 

這一次所消耗的迭代和循環永遠打印空列表。

>>> try: 
...  iterable = iter(range(4)) 
...  while True: 
...   print(list(next(iterable) for _ in range(2))) 
... except StopIteration: 
...  pass 
... 
[0, 1] 
[2, 3] 
[] 
[] 
[] 
etc. 

這種行爲的規則是什麼?

+0

http://stackoverflow.com/questions/16465313/how-yield-catches-stopiteration-exception –

回答

3

參考PEP479,它說,

發電機的互動與StopIteration異常,目前有些 不足爲奇,而可以隱瞞不明顯的錯誤。一個意想不到的異常 不應導致巧妙改變的行爲,但應導致嘈雜和容易調試的回溯。 目前,StopIteration在發生器函數內部偶然提出 將被驅動生成器的循環結構解釋爲 迭代結束。

(重點煤礦)

所以的list迭代傳遞發生器表達直到StopIteration誤差的構造被升高(通過調用next(iterable)沒有第二個參數)。又如:

def f(): 
    raise StopIteration # explicitly 

def g(): 
    return 'g' 

print(list(x() for x in (g, f, g))) # ['g'] 
print([x() for x in (g, f, g)]) # `f` raises StopIteration 

在另一方面,*解析的工作不同,因爲他們傳播StopIteration給調用者。


行爲,所提出的連接PEP是如下

如果StopIteration即將泡出一個發電機框架的,它被替換 與RuntimeError,這將導致next()呼叫(其 調用生成器)失敗,將該異常傳遞出去。從此 就像任何舊的例外。

的Python 3.5添加了可以使用

from __future__ import generator_stop 

這種行爲會默認在Python 3.7中啓用了generator_stop feature

+0

這種行爲的規則是什麼?爲什麼''[]''不能抑制''StopIteration''? – Yurim

+0

@Yurim我沒有任何參考,但我確信這個異常不會在這裏出現在'list()'外面。在內部它引發異常,並導致輸出爲* nothing *,然後列表拾取* nothing *並創建一個空列表。因爲列表理解也在'list()'內尋找同樣的異常 – percusse

相關問題