9

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

我正在考虑使用__del__关闭的方法,但是在网上阅读了一些之后,我有一些担忧。这是一个有效的使用模式吗?我可以确定内部资源将被__del__正确释放吗?

这次讨论提出了类似的问题,但没有找到令人满意的答案。我不想有一个显式的close方法,并且 usingwith不是一个选项,因为我的对象没有像 open-play-close 那样简单地使用,而是作为另一个使用它的更大对象的成员保存在 GUI 中运行时。

C++ 有完美的析构函数,可以安全地释放资源,所以我想 Python 也有一些共识。出于某种原因,情况似乎并非如此,社区中的许多人发誓反对__del__. 那有什么办法呢?

4

2 回答 2

8

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

您需要将连接包装在“上下文管理器”类中,该类处理语句使用的__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 应用程序的顶层创建的,因为这通常是获取数据库等资源的地方。

于 2009-06-10T10:51:46.730 回答
6

您可以创建一个连接模块,因为模块在整个应用程序中保留相同的对象,并注册一个函数以将其与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 甚至“更好”,因为它有一个垃圾收集器。

于 2009-06-10T11:09:59.890 回答