2016-12-25 56 views
3

代碼

def gen(): 
    try: 
     for i in range(5): 
      yield i 
    except Exception as e: 
     print('Caught: ' + str(e)) 
    finally: 
     print('I am done') 

for x in gen(): 
    print(x) 
    if x == 2: 
     raise Exception('Catch me?') 

輸出

0 
1 
2 
I am done 
Traceback (most recent call last): 
    File "test.py", line 13, in <module> 
    raise Exception('Catch me?') 
Exception: Catch me? 

問題條款

爲什麼代碼執行finally條款而不是except條款?的Python:嘗試...除了......終於在發電機

請給予解釋與參考。

+1

你在'gen()'函數外面引發異常,所以它沒有捕獲它。並且'finally'總是被執行。 – furas

+1

因爲'finally'每次執行時代碼是否失敗(它就像是一個清理),並且你在異常發生器之外引發了異常,所以它不知道它 – danidee

+0

嘗試''g = gen() ; g.throw(ValueError)'''。 – wwii

回答

4

發電機功能的主體將只運行迭代的for循環。也就是說,for循環是指這樣的:

  1. 從發電機獲取下一個值
  2. 運行循環體
  3. 回到步驟1

只有步驟1涉及實際內運行的代碼發電機功能。由於生成器函數中的try塊內的代碼不會引發任何異常,因此except子句沒有任何可捕獲的。子句執行finally,因爲它總是執行(這就是finally的用途)。

在生成器上使用循環並不意味着整個循環體在生成器函數的「內部」運行。這意味着一次只能從發生器中獲取一個值,直到耗盡。循環體仍然在自己的範圍內執行,與生成器函數分開。

+0

因此,如果在具有'finally'子句的生成器之外引發異常,那麼該子句何時運行?如果主函數使用多個生成器,每個生成器都有'finally'子句呢?他們按什麼順序執行? – Cyker

+1

@Cyker:如果這是你的問題,你應該編輯你的問題來問它。當'try'塊中的代碼結束時,會執行'finally'子句。如果你的發生器被掛在'try'塊內,那麼finally子句將不會被執行,直到發生器關閉(如果有的話)。 – BrenBarn