Python: очистить буфер перед завершением программы через финализатор - PullRequest
3 голосов
/ 23 декабря 2008

Я сохраняю кэш транзакций для сброса (в постоянное хранилище) в случае завершения создания водяного знака или объекта. Поскольку __del__ больше не гарантирует, что будет вызываться для каждого объекта, является ли подходящим подходом для подключения аналогичной функции (или __del__) к atexit.register (во время инициализации)?

Если я не ошибаюсь, это будет вызывать объект, к которому привязан метод, до завершения программы. Это вряд ли проблема, но может быть есть более элегантное решение?

Примечание: я знаю, что использование __del__ неидеально, потому что может вызывать неуловимые исключения , но я не могу придумать другой способ сделать это, кроме каскадных finalize() вызовов через мою программу. ТИА!

Ответы [ 5 ]

4 голосов
/ 23 декабря 2008

Если вам нужно обрабатывать ресурсы, предпочтительным способом является явный вызов метода close() или finalize(). Взгляните на оператор with, чтобы абстрагировать его. В вашем случае модуль weakref может быть вариантом. Кэшированный объект может быть собран системой из-за мусора и вызван их метод __del__(), или вы завершите их, если они все еще живы.

3 голосов
/ 23 декабря 2008

Я бы сказал atexit или попытался бы проверить, можно ли изменить код, чтобы он мог быть выражен с помощью with_statement, который по умолчанию равен __future__ в 2.5 и в 2.6. 2.5 включает в себя модуль contextlib для упрощения. Я сделал что-то подобное при использовании Canonical's Storm ORM.

из future import with_statement

@contextlib.contextmanager
def start_transaction(db):
  db.start()
  yield
  db.end()

with start_transaction(db) as transaction:
  ...

В случае не-db, вы можете просто зарегистрировать объекты, которые должны быть сброшены глобальными объектами, а затем использовать нечто подобное. Преимущество этого подхода состоит в том, что он сохраняет явные вещи.

2 голосов
/ 24 декабря 2008

Если вам не нужно, чтобы ваш объект был живым во время выполнения сброса, вы можете использовать слабые ссылки

Это похоже на предложенное вами решение, но вместо использования реальной ссылки сохраните список слабых ссылок с функцией обратного вызова для выполнения сброса. Таким образом, ссылки не будут поддерживать эти объекты в живых, и вы не столкнетесь с проблемами циклического мусора с __del__ методами.

Вы можете пробежаться по списку слабых ссылок на завершение, чтобы вручную сбросить все еще живые данные, если это необходимо гарантировать в определенный момент.

2 голосов
/ 23 декабря 2008

Поместите следующее в файл с именем destructor.py

import atexit

objects = []

def _destructor():
    global objects
    for obj in objects:
        obj.destroy()
    del objects

atexit.register(_destructor)

теперь используйте это так:

import destructor

class MyObj(object):
    def __init__(self):
        destructor.objects.append(self)
        # ... other init stuff
    def destroy(self):
        # clean up resources here
0 голосов
/ 23 декабря 2008

Я думаю, atexit - это путь сюда.

...