Ответ 1
Для управления ресурсами (например, файлами) в Python рекомендуется использовать ключевое слово with
, которое автоматически освобождает ресурсы (т.е. Очищает, как закрытие файлов); это доступно из Python 2.5.
Из Python 3.2, вы можете использовать tempfile.TemporaryDirectory()
вместо 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; см. Николас Бишопс ответ на tempfile.TeventDirectory контекстный менеджер в Python 2.7.
Легко и поучительно накатить свой собственный класс, называемый контекстным менеджером. Возвращаемое значение метода __enter__()
привязано к цели предложения as
, в то время как метод __exit__()
вызывается при выходе из контекста - даже по исключению - и выполнении очистки.
import shutil
import tempfile
class TemporaryDirectory(object):
"""Context manager for tempfile.mkdtemp() so it 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)
Вы можете упростить это с @contextlib.contextmanager
декоратора @contextlib.contextmanager
, поэтому вам не нужно писать менеджер контекста вручную. Код перед yield
выполняется при входе в контекст, полученное значение привязывается к цели as
, а код после yield
выполняется при выходе из контекста. По сути, это сопрограмма, которая заключает в себе получение и освобождение ресурса, а выход yield
к управлению набором (телом) предложения with
. Обратите внимание, что здесь вам не нужно иметь 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)
Как просто отмечает Lizl, если вы не возражаете против уже удаляемого каталога (который, как предполагает приведенный выше код, не происходит), вы можете поймать исключение "Нет такого файла или каталога" следующим образом:
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
, см.: