2014-11-22 33 views
6

上下文管理器定義安裝/清除功能__enter____exit__。真棒。我想保留一個作爲成員變量。當我的類對象超出作用域時,我希望執行此清理。這基本上是我理解的行爲是使用C++構造函數/析構函數自動發生的。Python上下文託管成員變量?

class Animal(object): 

    def __init__(self): 
     self.datafile = open("file.txt") # This has a cleanup function 
     # I wish I could say something like... 
     with open("file.txt") as self.datafile: # uh... 

    def makeSound(self): 
     sound = self.datafile # I'll be using it later 

# Usage... 
if True: 
    animal = Animal() 
# file should be cleaned up and closed at this point. 

回答

1

Python沒有做C++ - 風格RAII(「資源獲取就是初始化」,意思是任何你在構造函數中獲取,你在析構函數釋放)。實際上,除C++之外,幾乎沒有沒有語言做C++風格的RAII。 Python的上下文管理和with語句要實現這一C++確實有RAII同樣的事情不同方式,而大多數其他語言做finally陳述,guard等語句(Python同時finally,當然)。


你是什麼意思的「當我的類對象超出範圍」?

物體不超出範圍;引用(或變量,或名稱,無論你喜歡)做什麼。在最後一個引用超出範圍之後的一段時間(對於CPython來說,這是立即的,除非它涉及參考循環;對於其他實現,通常不會),則該對象將被垃圾收集。


如果你想要做一些清理工作時,你的對象是垃圾回收,您使用的__del__方法。但這很少是你真正想要的。 (事實上​​,有的班級有__del__方法只是爲了警告他們忘了清理用戶,而不是默默地收拾。)


更好的解決方案是讓Animal本身上下文管理,所以它可以管理其他上下文管理器 - 或者只是明確地管理事情。然後,你可以這樣寫:

if True: 
    with Animal() as animal: 
     # do stuff 
    # now the file is closed 

下面是一個例子:

class Animal(object): 

    def __init__(self): 
     self.datafile = open("file.txt") 

    def __enter__(self): 
     return self 

    def __exit__(self, type, value, traceback): 
     self.datafile.close() 

    def makeSound(self): 
     sound = self.datafile # I'll be using it later 

(剛脫落的__exit__結束像這意味着,呼籲self.datafile.close()後,我們成功地做什麼,如果沒有異常,或者,如果有一個重新提出同樣的例外。所以,你不必寫什麼明確要做到這一點。)


但通常,如果你打算要將課程轉換爲上下文管理器,還需要添加明確的close。就像文件一樣。一旦你這樣做,你真的不需要將Animal加入到上下文管理器中;你可以使用closing

2

我給班close功能,如果它是有道理的,然後使用closing情況管理器:

class MyClass(object): 
    def __init__(self): 
     self.resource = acquire_resource() 

    def close(): 
     release_resource(self.resource) 

,然後用它喜歡:

from contextlib import closing 

with closing(MyClass()) as my_object: 
    # use my_object