我正在创建一个类,我想在其中生成一个文件夹的临时工作空间,该文件夹将在对象的生命周期中持续存在,然后被删除。我在def init 中使用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)
还有其他/更好的方法来处理此清理工作吗?我正在阅读'有',但它似乎只是在一个函数中有用。
答案 0 :(得分:39)
警告:你永远不能保证将删除临时文件夹,因为用户可能总是难以杀死你的进程,然后它就无法运行其他任何东西。
那说,做
temp_dir = tempfile.mkdtemp()
try:
<some code>
finally:
shutil.rmtree(temp_dir)
由于这是一个非常常见的操作,Python有一种特殊的方法来封装“做某事,执行代码,清理”:上下文管理器。您可以按如下方式编写自己的代码:
@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__
将删除它。
答案 1 :(得分:9)
处理临时文件和目录的好方法是通过上下文管理器。这是您使用tempfile.TemporaryFile或tempfile.NamedTemporaryFile的方法 - 一旦您退出with
语句(通过正常退出,返回,异常或其他任何内容),它就是内容将从文件系统中删除。
对于Python 3.2+,它内置为tempfile.TemporaryDirectory:
import tempfile
with tempfile.TemporaryDirectory() as temp_dir:
... do stuff ...
对于早期的Python版本,您可以轻松创建自己的上下文管理器,以完成相同的操作。这里与@katrielalex答案的不同之处在于将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
),则目录将无法清除。
答案 2 :(得分:2)
如Bluewind所述,您必须确保将上下文管理器的yield部分包装在try:finally语句中,否则任何异常都不会在上下文管理器中真正正确处理。
在生成器产生的点处,执行嵌套在with语句中的块。然后在退出块之后恢复发生器。如果块中发生未处理的异常,则在生成器发生的点处将其重新加入。因此,您可以使用try ... except ... finally语句来捕获错误(如果有),或确保进行一些清理。如果仅为了记录异常或执行某些操作(而不是完全禁止它)而捕获异常,则生成器必须重新加载该异常。否则,生成器上下文管理器将向with语句指示已处理异常,并且将继续执行紧跟在with语句之后的语句。
此外,如果您使用的是Python 3.2+,那么您应该查看this little gem,其中包含了以上所有内容,并且很适合您
tempfile.TemporaryDirectory(suffix ='',prefix ='tmp',dir = None)
此函数使用mkdtemp()创建临时目录(提供的参数直接传递给基础函数)。生成的对象可以用作上下文管理器(请参阅使用语句上下文管理器)。完成上下文(或销毁临时目录对象)后,将从文件系统中删除新创建的临时目录及其所有内容。
可以从返回对象的name属性中检索目录名称。
可以通过调用cleanup()方法显式清理目录。
3.2版中的新功能。
答案 3 :(得分:2)
使用contextlib
的另一种方法是使对象可以关闭,并使用closing
上下文管理器。
class MyClass:
def __init__(self):
self.tempfolder = tempfile.mkdtemp()
def do_stuff():
pass
def close(self):
if os.path.exists(self.tempfolder):
shutil.rmtree(self.tempfolder)
然后使用上下文管理器:
from contextlib import closing
with closing(MyClass()) as my_object:
my_object.do_stuff()
答案 4 :(得分:1)
其他答案指出,您可以使用contextmanager或要求您的用户显式调用某种类型的清理功能。如果可以的话,这些都是很棒的事情。但是,有时没有地方进行此清理,因为您在大型应用程序内部,并且嵌套了多个层次,而上面没有人拥有清理方法或上下文管理器。
在这种情况下,您可以使用atexit:https://docs.python.org/2/library/atexit.html
import atexit
class MyClass:
def __init__(self):
self.tempfolder = tempfile.mkdtemp()
atexit.register(shutil.rmtree, self.tempfolder)
def ... #other stuff