清理Python类中临时文件夹的正确方法

2024-04-29 22:09:17 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在创建一个类,我想在其中生成一个文件夹的临时工作区,该工作区将在对象的生命周期内持续存在,然后被删除。我正在使用defin I t中的tempfile.mkdtemp()来创建空间,但我已经读到不能依赖于被调用的del。

我想要这样的东西:

class MyClass:
  def __init__(self):
    self.tempfolder = tempfile.mkdtemp()

  def ... #other stuff

  def __del__(self):
    if os.path.exists(self.tempfolder): shutil.rmtree(self.tempfolder)

有没有其他更好的方法来处理这次清理?我读过关于“with”的文章,但它似乎只对函数有帮助。


Tags: 对象self文件夹initdefmyclass空间tempfile
3条回答

处理临时文件和目录的一个好方法是通过上下文管理器。这就是如何使用tempfile.TemporaryFiletempfile.NamedTemporaryFile——一旦退出with语句(通过普通的exit、return、exception或其他方式),文件/目录及其内容将从文件系统中删除。

对于Python 3.2+,它内置为tempfile.TemporaryDirectory

import tempfile

with tempfile.TemporaryDirectory() as temp_dir:
    ... do stuff ...

对于早期的Python版本,您可以轻松地创建自己的上下文管理器来执行完全相同的操作。这里与@katrialex answer的不同之处在于将args传递给mkdtemp()和try/finally块,以确保在引发异常时清除目录。

import contextlib
import shutil

@contextlib.contextmanager
def temporary_directory(*args, **kwargs):
    d = tempfile.mkdtemp(*args, **kwargs)
    try:
        yield d
    finally:
        shutil.rmtree(d)


# use it
with temporary_directory() as temp_dir:
    ... do stuff ...

注意,如果进程被硬终止(例如kill -9),那么目录将不会被清理。

注意:您永远不能保证temp文件夹会被删除,因为用户总是会硬终止您的进程,然后它就不能运行其他任何东西。

也就是说,做

temp_dir = tempfile.mkdtemp()
try:
    <some code>
finally:
    shutil.rmtree(temp_dir)

由于这是一个非常常见的操作,Python有一种特殊的方式来封装“do something,execute code,clean up”:acontext manager。你可以自己写如下:

@contextlib.contextmanager
def make_temp_directory():
    temp_dir = tempfile.mkdtemp()
    try:
        yield temp_dir
    finally:
        shutil.rmtree(temp_dir)

把它当作

with make_temp_directory() as temp_dir:
    <some code>

(请注意,这使用@contextlib.contextmanager快捷方式创建上下文管理器。如果要按原来的方式实现一个类,则需要使用__enter____exit__方法创建一个自定义类;__enter__将创建并返回临时目录,然后__exit__将其删除。

Bluewind所述,您必须确保将上下文管理器的yield部分包装在try:finally语句中,否则任何异常都不会在上下文管理器中得到正确处理。

来自Python 2.7 docs

At the point where the generator yields, the block nested in the with statement is executed. The generator is then resumed after the block is exited. If an unhandled exception occurs in the block, it is reraised inside the generator at the point where the yield occurred. Thus, you can use a try...except...finally statement to trap the error (if any), or ensure that some cleanup takes place. If an exception is trapped merely in order to log it or to perform some action (rather than to suppress it entirely), the generator must reraise that exception. Otherwise the generator context manager will indicate to the with statement that the exception has been handled, and execution will resume with the statement immediately following the with statement.

另外,如果您使用的是Python 3.2+,那么应该检查一下this little gem,它为您很好地包装了上述所有内容

tempfile.TemporaryDirectory(suffix='', prefix='tmp', dir=None)

This function creates a temporary directory using mkdtemp() (the supplied arguments are passed directly to the underlying function). The resulting object can be used as a context manager (see With Statement Context Managers). On completion of the context (or destruction of the temporary directory object), the newly created temporary directory and all its contents are removed from the filesystem.

The directory name can be retrieved from the name attribute of the returned object.

The directory can be explicitly cleaned up by calling the cleanup() method.

New in version 3.2.

相关问题 更多 >