2015-01-26 80 views
2

我想我已經讀過with中的異常不允許__exit__被調用正確。如果我在這張紙上錯了,請原諒我的無知。python如何安全地處理上下文管理器中的異常

所以我有一些僞代碼在這裏,我的目標是使用在__enter__記錄起始日期時間,並返回一個鎖的ID鎖的上下文,並在__exit__記錄末端datetime和釋放鎖:

def main(): 
    raise Exception 

with cron.lock() as lockid: 
    print('Got lock: %i' % lockid) 
    main() 

除了安全地存在上下文之外,我還能如何提出錯誤?

注意:我故意在這個僞代碼中引發基本異常,因爲我想在任何異常時安全地退出,而不僅僅是預期的異常。

注意:替代/標準的併發預防方法是不相關的,我想將這些知識應用到任何一般的上下文管理中。我不知道不同的背景是否有不同的怪癖。

PS。 finally塊與相關嗎?

+1

你在哪裏得到這些信息?我的理解是''有''上下文是*設計用於*處理清理如果發生任何未處理的異常。 – 2015-01-26 20:16:33

+0

@JoelCornett我認爲我從SO頁面獲得了專門處理嵌套上下文的信息。 – ThorSummoner 2015-01-26 20:42:33

回答

9

如果上下文管理器被異常中斷,則__exit__方法被調用爲正常。實際上,傳遞給__exit__的參數都與處理這種情況有關!從the docs

object.__exit__(self, exc_type, exc_value, traceback)

退出運行時上下文與此相關的對象。參數描述導致上下文退出的異常。如果上下文沒有異常退出,則所有三個參數都將爲None。

如果提供了一個異常,並且該方法希望抑制異常(即防止它被傳播),它應該返回一個真值。否則,在退出此方法後,異常將被正常處理。

請注意,__exit__()方法不應該重新傳入傳入的異常;這是來電者的責任。

所以你可以看到,__exit__方法將被執行,然後,在默認情況下,任何的異常將被退出上下文管理器後重新提出。您可以通過創建一個簡單的上下文管理與例外打破它測試這個自己:

DummyContextManager(object): 
    def __enter__(self): 
     print('Entering...') 
    def __exit__(self, exc_type, exc_value, traceback): 
     print('Exiting...') 
     # If we returned True here, any exception would be suppressed! 

with DummyContextManager() as foo: 
    raise Exception() 

當你運行這段代碼,你會看到你想要的東西(可能是壞了,因爲print趨於落得回溯的中間):

Entering... 
Exiting... 
Traceback (most recent call last): 
    File "C:\foo.py", line 8, in <module> 
    raise Exception() 
Exception