Подтвердить что ты не робот

Правильный способ очистки временной папки в классе Python

Я создаю класс, в котором я хочу создать временное рабочее пространство папок, которое будет сохраняться для жизни объекта, а затем будет удалено. Я использую tempfile.mkdtemp() в def init, чтобы создать пробел, но я прочитал, что я не могу полагаться на вызываемый 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)

Есть ли другой/лучший способ справиться с этой очисткой? Я читал о "с", но, похоже, он полезен только в функции.

4b9b3361

Ответ 1

Предостережение: вы никогда не сможете гарантировать, что временная папка будет удалена, потому что пользователь всегда может убить ваш процесс, а затем ничего не может запустить.

Тем не менее,

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__ создаст и вернет каталог temp и __exit__ удалит его.

Ответ 2

Хороший способ справиться с временными файлами и каталогами - через менеджер контекста. Вот как вы можете использовать tempfile.TemporaryFile или tempfile.NamedTemporaryFile - после того, как вы вышли из инструкции with (через обычный выход, возврат, исключение или что-то еще), файл/каталог и его содержимое будут удалены из файловой системы.

Для Python 3.2+ он встроен в tempfile.TemporaryDirectory:

import tempfile

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

Для более ранних версий Python вы можете легко создать свой собственный менеджер контекстов, чтобы сделать то же самое. Отличие от ответа @katrielalex заключается в передаче аргументов 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), то каталоги не будут очищены.

Ответ 3

Как указано Bluewind, вы должны обязательно обернуть часть доходности контекстного менеджера внутри инструкции try: finally, иначе любые исключения на самом деле не будут корректно обрабатываться внутри диспетчера контекстов.

От Python 2.7 docs

В момент, когда генерирует генератор, выполняется блок, вложенный в оператор с. Затем генератор возобновляется после выхода блока. Если в блоке возникает необработанное исключение, оно ререйзируется внутри генератора в точке, где произошел выход. Таким образом, вы можете использовать команду try... except... finally, чтобы уловить ошибку (если она есть) или убедиться, что происходит некоторая очистка. Если исключение попадает в ловушку только для того, чтобы зарегистрировать его или выполнить какое-либо действие (а не полностью его подавить), генератор должен сделать репозицию этого исключения. В противном случае диспетчер контекста генератора укажет в инструкции с, что обработано исключение, и выполнение возобновится с оператором сразу после оператора с.

Также, если вы используете Python 3.2+, вы должны проверить этот маленький драгоценный камень, который имеет все вышеперечисленное, /p >

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

Эта функция создает временный каталог с использованием mkdtemp() (предоставленные аргументы передаются непосредственно базовой функции). Полученный объект можно использовать в качестве менеджера контекста (см. Раздел "Контекстные менеджеры выражений" ). По завершении контекста (или уничтожения временного объекта каталога) вновь созданный временный каталог и все его содержимое удаляются из файловой системы.

Имя каталога можно получить из атрибута name возвращаемого объекта.

Каталог можно явно очистить, вызвав метод cleanup().

Новое в версии 3.2.

Ответ 4

Другая альтернатива, использующая 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()