Очистка внутреннего pysqlite соединения при разрушении объекта - PullRequest
6 голосов
/ 10 июня 2009

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

Я подумываю использовать метод __del__ для закрытия, но после некоторого чтения онлайн у меня возникают проблемы. Это действительный шаблон использования? Могу ли я быть уверен, что внутренние ресурсы будут освобождены в __del__ правильно?

Эта дискуссия подняла аналогичный вопрос, но не нашла удовлетворительного ответа. Я не хочу иметь явный метод close, и использование with не вариант, потому что мой объект не используется так просто, как open-play-close, но сохраняется как член другого, больший объект, который использует его во время работы в графическом интерфейсе.

В C ++ есть отлично работающие деструкторы, в которых можно безопасно высвободить ресурсы, поэтому я думаю, что в Python тоже есть что-то согласованное. По некоторым причинам, похоже, что это не так, и многие в сообществе клянутся против __del__. Какая альтернатива, тогда?

Ответы [ 2 ]

6 голосов
/ 10 июня 2009

Читайте с оператором . Вы описываете его вариант использования.

Вам нужно будет обернуть ваше соединение в класс «Context Manager», который обрабатывает методы __enter__ и __exit__, используемые оператором with.

См. PEP 343 для получения дополнительной информации.


Редактировать

"мой объект не используется так просто, как open-play-close, но сохраняется как элемент другого, более крупного объекта"

class AnObjectWhichMustBeClosed( object ):
    def __enter__( self ):
        # acquire
    def __exit__( self, type, value, traceback ):
        # release
    def open( self, dbConnectionInfo ):
        # open the connection, updating the state for __exit__ to handle.

class ALargerObject( object ):
    def __init__( self ):
        pass
    def injectTheObjectThatMustBeClosed( self, anObject ):
        self.useThis = anObject

class MyGuiApp( self ):
    def run( self ):
        # build GUI objects
        large = ALargeObject()
        with AnObjectWhichMustBeClosed() as x:
            large.injectTheObjectThatMustBeClosed( x )
            mainLoop()

Некоторые люди называют это «Внедрение зависимостей» и «Инверсия контроля». Другие называют это паттерном Strategy . ObjectThatMustBeClosed - это стратегия, включенная в какой-то более крупный объект. Сборка создается на верхнем уровне приложения с графическим интерфейсом, поскольку именно там обычно создаются такие ресурсы, как базы данных.

5 голосов
/ 10 июня 2009

Вы можете создать модуль подключения, поскольку модули сохраняют один и тот же объект во всем приложении и регистрируют функцию, чтобы закрыть его с помощью модуля atexit

# db.py:
import sqlite3
import atexit

con = None

def get_connection():
    global con
    if not con:
        con = sqlite3.connect('somedb.sqlite')
    atexit.register(close_connection, con)
    return con

def close_connection(some_con):
    some_con.commit()
    some_con.close()

# your_program.py
import db
con = db.get_connection()
cur = con.cursor()
cur.execute("SELECT ...")

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

Если это не так, то вы можете использовать деструктор.

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

Кроме того, то, что вы сказали о C ++, неверно. Если вы используете деструкторы в C ++, они вызываются либо по завершении блока, определяющего объект (например, with в python), либо когда вы используете ключевое слово delete (которое освобождает объект, созданный с помощью new). Вне этого вы должны использовать явный close(), который не является деструктором. Так что это как python - python даже «лучше», потому что у него есть сборщик мусора.

...