To manage resources (like files) in Python, best practice is to use the with
keyword, which automatically releases the resources (i.e., cleans up, like closing files); this is available from Python 2.5.
From Python 3.2, you can use tempfile.TemporaryDirectory()
instead of tempfile.mkdtmp()
– this is usable in with
and automatically cleans up the directory:
from tempfile import TemporaryDirectory
with TemporaryDirectory() as temp_dir:
# ... do something with temp_dir
# automatically cleaned up when context exited
If you are using an earlier version of Python (at least 2.5, so have with
), you can use backports.tempfile; see Nicholas Bishop’s answer to tempfile.TemporaryDirectory context manager in Python 2.7.
It’s easy and instructive to roll your own class, called a
context manager. The return value of the __enter__()
method is bound to the target of the as
clause, while the __exit__()
method is called when the context is exited – even by exception – and performs cleanup.
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)
You can simplify this with the @contextlib.contextmanager
decorator, so you don’t need to write a context manager manually. The code prior to the yield
is executed when entering the context, the yielded value is bound to the target of the as
, and the code after the yield
is executed when exiting the context. This is fundamentally a coroutine that encapsulates the resource acquisition and release, with the yield
yielding control to the suite (body) of the with
clause. Note that here you do need to have a try...finally
block, as @contextlib.contextmanager
does not catch exceptions in the yield
– this just factors the resource management into a coroutine.
from contextlib import contextmanager
import tempfile
import shutil
@contextmanager
def TemporaryDirectory():
name = tempfile.mkdtemp()
try:
yield name
finally:
shutil.rmtree(name)
As simplylizz notes, if you don’t mind the directory already being deleted (which the above code assumes does not happen), you can catch the “No such file or directory” exception as follows:
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
You can compare with the standard implementation in tempfile.py
; even this simple class has had bugs and evolved over the years.
For background on with
, see: