Правильная доработка в Python

#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. Да, похоже, это именно то, что я искал. Спасибо!