13

我正在使用一个临时目录,我想确保它在程序关闭时被删除(无论程序是否成功)。我正在使用tempfile.mkdtemp创建目录并将创建的字符串放入其子类中str删除其__del__命令上的目录:

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 会自动删除/垃圾收集所有变量吗?如果没有,我如何确保该目录被删除?

有关在 Python 中创建析构函数方法的相关信息。似乎只要 TempDir 对象不引用其他任何东西,使用__del__它来破坏它应该没问题。

4

3 回答 3

19

我不会使用__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)
于 2012-06-10T00:28:47.253 回答
9

对于依赖于特定(半模拟)文件结构的存在的包测试套件,我需要类似的东西。对于许多测试模块,我并不总是知道将运行哪些测试以及以什么顺序运行,或者测试运行将如何退出。

根据__del__我的经验,在应用程序退出时使用是不可靠的。使用上下文管理器意味着重写测试文件以确保一切都很好地包装。相反,我使用atexit. 在<package>.tests.__init__我刚刚添加:

import atexit, shutil, tempfile

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

然后 Python 将shutil.rmtree(test_area)在退出时调用。如果需要,也可以添加用于错误处理的关键字参数。

于 2012-12-16T23:42:49.987 回答
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,它的行为将与程序结束完全相同。

于 2012-06-10T00:27:29.793 回答