2015-06-16 96 views
3

我寫了一個關於Python生成器的測試程序。但是我收到了一個不可預料的錯誤。我不知道如何解釋它。讓我告訴你的代碼:Python生成器中的GeneratorExit

def countdown(n): 
    logging.debug("Counting down") 
    while n > 0: 
     try: 
      yield n 
     except GeneratorExit: 
      logging.error("GeneratorExit") 
     n -= 1 


if __name__ == '__main__': 
    c = countdown(10) 
    logging.debug("value: %d", c.next()) 

我認爲它應該運行沒有任何問題。但輸出是:

# ./test.py 
[2015/06/16 04:10:49] DEBUG - Counting down  
[2015/06/16 04:10:49] DEBUG - value: 10 
[2015/06/16 04:10:49] ERROR - GeneratorExit 
Exception RuntimeError: 'generator ignored GeneratorExit' in <generator object countdown at 0x7f9934407640> ignored 

爲什麼在最後一行出現錯誤。我不知道爲什麼我觸發了GeneratorExit異常。有沒有什麼事情我錯過了?我還將代碼輸入到交互式python shell中,並且一切正常。這怎麼會發生?

回答

3

當生成器對象在程序結束時被垃圾回收時,將調用它的close()方法,這會在生成器內引發GeneratorExit異常。通常這不會被捕獲並導致發生器退出。

由於您發現異常並繼續產生另一個值,因此會導致產生RuntimeError。如果你發現了GeneratorExit異常,你需要對其進行重新評估,或者退出該函數而不會產生任何其他內容。

11

假設你有以下發電機:

def gen(): 
    with open('important_file') as f: 
     for line in f: 
      yield line 

,你next一次,把它扔掉:

g = gen() 
next(g) 
del g 

發電機的控制流永遠不會離開with塊,因此該文件沒有按」關閉。爲防止發生這種情況,當生成器被垃圾回收時,Python會調用其方法close,這會在生成器最後yield編輯點時引發GeneratorExit異常。這個例外是爲了觸發沒有機會運行的任何finally塊或上下文管理器__exit__

當你捕捉到GeneratorExit並繼續前進時,Python發現生成器沒有正確退出。由於這可能表明資源沒有正確釋放,Python會將其報告爲RuntimeError。