2012-06-10 53 views
7

我正在處理一個臨時目錄,我想確保它在程序關閉時被刪除(無論程序是否成功)。我使用tempfile.mkdtemp創建目錄,並把該刪除其__del__命令的目錄時創建成str一個子類的字符串:如何管理臨時目錄以保證在程序關閉時被刪除?

import shutil 
import tempfile 

class TempDir(str): 
    """ container for temporary directory. 
    Deletes directory when garbage collected/zero references """ 
    def __del__(self): 
     shutil.rmtree(self.__str__(), onerror=my_error_fn) 

dbdir = TempDir(tempfile.mkdtemp()) 

這裏就是我不知道:如果程序關閉或一個KeyboardInterrupt發生了,Python會自動刪除/垃圾收集所有的變量嗎?如果沒有,我如何確保目錄被刪除?

有關creating destructor methods in Python的相關信息。似乎只要TempDir對象沒有引用其他任何東西,使用__del__來破壞它應該沒問題。

+1

當您測試它時發現了什麼?每次Ctrl + C時是否執行'__del__'? –

+0

好吧,只是添加了我的測試結果 - 非常感謝您的建議@JoelCornett! –

+0

考慮除'__del__'之外還使用'atexit'模塊。 – martineau

回答

17

我不會使用__del__方法,語義不可靠,並且可能會干擾垃圾回收。使用上下文管理器:定義__enter____exit__方法,並將該對象用於with語句中。很明顯,這是明確的,它將毫無顧慮地工作。

或者,另一種方法,使上下文管理器:

@contextlib.contextmanager 
def tempdir(prefix='tmp'): 
    """A context manager for creating and then deleting a temporary directory.""" 
    tmpdir = tempfile.mkdtemp(prefix=prefix) 
    try: 
     yield tmpdir 
    finally: 
     shutil.rmtree(tmpdir) 
+1

關於這個問題:我想用這個目錄創建一些文件,然後只刪除它:(1)當程序結束或(2)當目錄中的文件的所有引用都不存在時(意味着在我的實現中,所有對TempDir類的引用都將被刪除。)這種格式能夠做到嗎? –

+1

我想在這裏有一個額外的觀點:在with語句中使用它並不是真正的工作 - 使用該軟件包的人將會操縱,添加/刪除文件,臨時文件應該對它們透明。它似乎不適合上下文管理器。 –

+0

Jeff,你是對的,當資源的生命週期與詞法範圍匹配時,上下文管理器是很好的。上下文管理器仍然可以在程序的頂層使用來處理程序退出,而其他對象引用可以顯式管理來處理引用該目錄的文件。 –

1

它只在程序結束時纔會刪除所有內容(就像通常那樣)。

爲了說明,這裏是我使用的代碼:

import tempfile 
import shutil 
import os 

class TempDir(str): 
    """ container for temporary directory. Deletes directory when garbage 
    collected/zero references """ 
    def __del__(self): 
     print "deleting temporary files in directory {}".format(self.__str__()) 
     shutil.rmtree(self.__str__(), onerror=delete_dir_handler) 

def delete_dir_handler(listdir_fn, dirname, exception): 
    try: 
     for fileobj in listdir_fn(dirname): 
      os.remove(fileobj) 
     os.removedirs(dirname) 
    except (AttributeError, OSError, TypeError): 
     print exception[1] 
     print "Sorry. Couldn't delete directory {}.".format(dirname) 
     raise 

test = TempDir(tempfile.mkdtemp()) 

輸出:

$ python my_file.py 
deleting temporary files in directory /var/folders/A9/A9xrfjrXGsq9Cf0eD2jf0U+++TI/-Tmp-/tmpG3h1qD 

如果您在交互模式下運行它,它不會刪除,直到你退出程序。

$ python -i my program 
>>> # pressed Ctrl-C here 
KeyboardInterrupt 
>>> # again, Ctrl-C 
KeyboardInterrupt 
>>> # Ctrl-D to exit 
deleting temporary files in directory /var/folders/A9/A9xrfjrXGsq9Cf0eD2jf0U+++TI/-Tmp-/tmpMBGt5n 

最後,如果你添加一個raw_input('')行添加到文件,它將如果你按下Ctrl-C行爲完全一樣的程序結束。

7

我需要一個封裝測試套件,依賴於特定的存在類似的東西(半嘲笑)文件結構。對於許多測試模塊,我並不總是知道哪些測試將以什麼順序運行,或測試運行將如何退出。

在應用程序退出時使用__del__在我的經驗中不可靠。使用上下文管理器意味着重寫測試文件以確保一切都很好地包裝。相反,我使用atexit。在<package>.tests.__init__我只是說:

import atexit, shutil, tempfile 

test_area = tempfile.mkdtemp() 
atexit.register(shutil.rmtree, test_area) 

Python會,然後在出口處調用shutil.rmtree(test_area)。如果需要,還可以添加錯誤處理的關鍵字參數。

相關問題