2012-06-10 23 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)。如果需要,还可以添加错误处理的关键字参数。

相关问题