在对象销毁时清理内部pysqlite连接

时间:2009-06-10 10:39:34

标签: python destructor pysqlite

我有一个内部数据库连接的对象,它在整个生命周期内都是活动的。在程序运行结束时,必须提交并关闭连接。到目前为止,我使用了一个显式的close方法,但这有点麻烦,特别是当调用代码中发生异常时。

我正在考虑使用__del__方法进行关闭,但在线阅读之后,我有一些担忧。这是一种有效的使用模式吗?我可以确定正确地在__del__中释放内部资源吗?

This discussion提出了类似的问题,但没有找到令人满意的答案。我不希望有一个明确的close方法,并且使用with不是一个选项,因为我的对象不像开放式播放关闭那样简单,而是保持为另一个更大的对象的成员,它在GUI中运行时使用它。

C ++具有完美的工作析构函数,可以安全地释放资源,所以我认为Python也有同意的东西。出于某种原因,情况似乎并非如此,社区中的许多人发誓反对__del__。那么替代方案是什么?

2 个答案:

答案 0 :(得分:6)

阅读with声明。您正在描述其用例。

您需要将您的连接包装在“Context Manager”类中,该类处理__enter__语句使用的__exit__with方法。

有关详细信息,请参阅PEP 343


修改

“我的对象不像开放式游戏那样简单使用,而是作为另一个更大的对象的成员保存”

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()

有些人称之为“依赖注入”和“控制反转”。其他人称之为策略模式。 “ObjectThatMustBeClosed”是一种策略,插入一些更大的对象。程序集是在GUI应用程序的顶层创建的,因为这通常是获取数据库等资源的地方。

答案 1 :(得分:5)

您可以创建一个连接模块,因为模块在整个应用程序中保留相同的对象,并注册一个函数以使用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 ...")

这种假设是基于这样的假设:应用程序中的连接看起来像是一个模块全局提供的单个实例(单例)。

如果不是这样,那么你可以使用析构函数。

然而,析构函数不能很好地处理垃圾收集器和循环引用(您必须在调用析构函数之前自己删除循环引用),如果不是这种情况(您需要多个连接),那么您可以使用析构函数。只是不要保持循环引用,否则你必须自己打破它们。

另外,你所说的关于C ++的内容是错误的。如果在C ++中使用析构函数,则在定义对象的块完成时(如python的with)或使用delete关键字(取消分配使用new创建的对象时调用它们)。除此之外,您必须使用不是析构函数的显式close()。所以它就像python-python甚至“更好”,因为它有一个垃圾收集器。