要在 Python 中管理资源(如文件),最佳实践是使用 @987654321@ 关键字,它会自动释放资源(即清理,如关闭文件);这在 Python 2.5 中可用。
从 Python 3.2 开始,您可以使用 @987654322@ 代替 tempfile.mkdtmp() - 这可用于 with 并自动清理目录:
from tempfile import TemporaryDirectory
with TemporaryDirectory() as temp_dir:
# ... do something with temp_dir
# automatically cleaned up when context exited
如果您使用的是较早版本的 Python(至少 2.5,with 也是如此),您可以使用 backports.tempfile;见Nicholas Bishop’s answer 到tempfile.TemporaryDirectory context manager in Python 2.7。
创建自己的课程既简单又富有启发性,称为
context manager. __enter__() 方法的返回值绑定到as 子句的目标,而__exit__() 方法在上下文退出时被调用——即使是异常——并执行清理。
import shutil
import tempfile
class TemporaryDirectory(object):
"""Context manager for tempfile.mkdtemp() so it's usable with "with" statement."""
def __enter__(self):
self.name = tempfile.mkdtemp()
return self.name
def __exit__(self, exc_type, exc_value, traceback):
shutil.rmtree(self.name)
您可以使用 @987654327@ 装饰器简化此操作,因此您无需手动编写上下文管理器。 yield之前的代码在进入上下文时执行,yield值绑定到as的目标,yield之后的代码在退出上下文时执行。这基本上是一个封装资源获取和释放的coroutine,其中yield 将控制权交给with 子句的suite(正文)。请注意,这里您确实需要有一个try...finally 块,因为@contextlib.contextmanager 不会在yield 中捕获异常——这只是将资源管理纳入协程。
from contextlib import contextmanager
import tempfile
import shutil
@contextmanager
def TemporaryDirectory():
name = tempfile.mkdtemp()
try:
yield name
finally:
shutil.rmtree(name)
正如 simplelizz 所指出的,如果您不介意已经删除的目录(上面的代码假设不会发生这种情况),您可以捕获“没有这样的文件或目录”异常,如下所示:
import errno
# ...
try:
shutil.rmtree(self.name)
except OSError as e:
# Reraise unless ENOENT: No such file or directory
# (ok if directory has already been deleted)
if e.errno != errno.ENOENT:
raise
您可以与tempfile.py中的标准实现进行比较;即使是这个简单的类也有错误并且多年来不断发展。
有关with的背景,请参阅: