2015-12-02 70 views
-1

我打開上初始化一個套接字連接類,並且可以發送和接收某些消息來回對手。我使用with語句創建對象的一個​​實例。在我的課堂上,如果我在套接字上收到某些消息,我想明確關閉連接,並退出with聲明。呼叫`with`的__exit__明確和退出

我試圖這樣做,通過顯式調用self.\__exit__(None, None, None)

def __exit__(self, type, value, traceback): 
    print 'Closing Connection' 
    self.logout() 
    self.conn.close() 
    sys.exit(1) 

不過,我發現,我收到Closing Connection消息發回的兩倍,並運行到,因爲在第二次調用問題,不再有一個關閉的連接。檢查代碼時,我排除了我明確致電self.__exit__(None, None, None)的所有其他實例。這是怎麼回事?是sys.exit(1)不足以防止垃圾再次收集with(雖然從我讀過,這似乎是最「批准」的方式來做到這一點)?如何防止with聲明致電self.__exit__(None, None, None)。任何幫助,或在正確的方向點,將不勝感激!

+3

的'__exit__'方法當控制流離開'with'語句時總是被調用,不管這種情況如何。你不應該明確地調用它。如果你重構你的代碼,這樣會更好,所以你不需要這樣做。 –

+0

另外,在'__exit__'函數中有'sys.exit(1)'是不好的形式。 '__exit__'函數只能抑制異常或允許它們傳遞;他們不應該退出程序,因爲它們只是用於清理或資源管理。它隱藏了程序邏輯並使你的代碼難以閱讀。使用'語句從'頂級'''''sys.exit(1)'運行'''''''''''''''''因此很明顯你正在退出並顯示一個錯誤值。 – eestrada

+0

不要顯式調用__exit()__',那麼沒有問題。你可以從上下文管理器內部返回,或者你可以結束:這應該如何調用__exit()__'。 – msw

回答

0

一旦您在with聲明中,唯一不帶運行__exit__的方法是使用os._exit;那很糟。相反,如果您需要這種行爲,請明確從調用__enter__開始。或者改變你的班級,以確保它在兩次被打電話時不會兩次清理,就像@Kay在他的回答中所建議的那樣。或者說,作爲@IsmailBadawi表明在他的評論,重構你的代碼,所以你並不需要顯式調用__exit__

+0

當你說「明確地通過調用'__enter_'開始時,」你的意思是不使用'with'語句嗎?所以,創建對象。然後調用'obj .__輸入__()'? –

+0

@AmyD:是的,這確實是我明確調用'__enter__'的意思。但是,這不是你通常應該做的事情。我做過的唯一一次是在單元測試中作爲'setUp' /'tearDown'的一部分(甚至在沒有其他選項的情況下也是如此)。否則,讓'with'語句爲你調用'__enter__'和'__exit__'函數做好工作。所有你需要擔心的是你的'__exit__'函數如何處理異常,如果它甚至需要這樣做的話。 – eestrada

0

只需記住,如果你已經關閉了連接/日誌/東西:

class MyContext(object): 
    def __init__(self): 
     self.__already_closed = False 

    .... 

    def close(self): 
     if not self.__already_closed: 
      self.__already_closed = True 
      self.logout() 
      self.conn.close() 

    def __exit__(...): 
     self.close() 

甚至增加了「請不要清除」的方法:

def do_not_cleanup(self): 
     self.__already_closed = True