#python #garbage-collection #temporary-files #finalizer #del
Вопрос:
У меня есть несколько экземпляров, каждый из которых имеет уникальный временный файл для его использования (сохранение данных из памяти на диск и извлечение их позже).
Я хочу быть уверен, что в конце дня все эти файлы будут удалены. Тем не менее, я хочу оставить место для детального контроля за их удалением. То есть некоторые файлы могут быть удалены раньше, если это необходимо (например, они слишком большие и больше не важны).
Каков наилучший / рекомендуемый способ достижения этой цели?
Возможно, мысли об этом
try-finalize
Блоки илиwith
операторы не являются опцией, так как у нас есть много файлов, время жизни которых может перекрывать друг друга. Кроме того, он вряд ли допускает возможность более тонкого контроля.- Из того, что я прочитал,
__del__
это также неосуществимый вариант, так как даже не гарантируется, что он в конечном итоге будет запущен (хотя мне не совсем ясно, каковы «рискованные» случаи). Кроме того (если это все еще так), библиотеки могут быть недоступны при__del__
запуске. tempfile
библиотека кажется многообещающей. Однако файл исчез после его простого закрытия, что, безусловно, облом, так как я хочу, чтобы они были закрыты (когда они не выполняют никаких операций), чтобы ограничить количество открытых файлов.- Библиотека обещает, что файл «будет уничтожен, как только он будет закрыт (включая неявное закрытие, когда объект собирается в мусор)».
Как они достигают неявного закрытия? Например, в C# я бы использовал (надежный) финализатор, которого
__del__
нет.
- Библиотека обещает, что файл «будет уничтожен, как только он будет закрыт (включая неявное закрытие, когда объект собирается в мусор)».
atexit
библиотека, по-видимому, является лучшим кандидатом, который может работать в качестве надежного завершителя, а__del__
не для реализации безопасного одноразового шаблона. Единственная проблема, по сравнению с финализаторами объектов, заключается в том, что он действительно запускается при выходе, что довольно неудобно (что делать, если объект, подлежащий сбору мусора ранее?).- Здесь вопрос все еще остается в силе. Как библиотека добивается того, чтобы методы всегда выполнялись? (За исключением действительно неожиданных случаев, с которыми трудно что-либо сделать)
В идеальном случае, кажется, что комбинация __del__
и atexit
библиотека может работать лучше всего. То есть очистка выполняется как по __del__
адресу, так и по методу , зарегистрированному в atexit
, в то время как повторная очистка будет запрещена. Если __del__
был вызван, зарегистрированный будет удален.
Единственная (но решающая) проблема заключается в том , что __del__
она не будет выполняться, если метод зарегистрирован в atexit
, потому что ссылка на объект существует вечно.
Таким образом, любое предложение, совет, полезная ссылка и так далее приветствуются.
Комментарии:
1. Как насчет того, чтобы поместить все пути, которые вы в конечном итоге хотите удалить, в список, и в какой-то момент вы пройдетесь по списку и удалите все существующие файлы?
2. @khelwood Спасибо вам за ваше предложение. Однако мне кажется, что это немного неудобно. Обычно лучше, когда объект освобождает свои ресурсы, поддерживая принцип сокрытия информации. Например, если временный файл заменен облачным хранилищем, код совершенно нереализованного места (в отношении изменения) необходимо переписать (не говоря уже о двух типах объектов, один с временным файлом, другой с облаком или даже более таких типов). Тем не менее, общий
dispose
вызов этих объектов определенно есть в меню, хотя я все равно предпочел бы автоматическую доработку (т. Е. с помощью GC).
Ответ №1:
Я предлагаю рассмотреть встроенный модуль weakref для этой задачи, более конкретно weakref.завершите простой пример:
import weakref
class MyClass:
pass
def clean_up(*args):
print('clean_up', args)
my_obj = MyClass()
weakref.finalize(my_obj, clean_up, 'arg1', 'arg2', 'arg3')
del my_obj # optional
при запуске он выведет
clean_up ('arg1', 'arg2', 'arg3')
Обратите внимание, что это clean_up
будет выполнено даже без del
-ing my_obj
(вы можете удалить последнюю строку кода, и поведение не изменится). clean_up
вызывается после того, как все сильные ссылки на my_obj исчезли или закончились (например, при использовании atexit
модуля).
Комментарии:
1. Да, похоже, это именно то, что я искал. Спасибо!