我有一个内部数据库连接的对象,它在整个生命周期内都是活动的。在程序运行结束时,必须提交并关闭连接。到目前为止,我使用了一个显式的close
方法,但这有点麻烦,特别是当调用代码中发生异常时。
我正在考虑使用__del__
方法进行关闭,但在线阅读之后,我有一些担忧。这是一种有效的使用模式吗?我可以确定正确地在__del__
中释放内部资源吗?
This discussion提出了类似的问题,但没有找到令人满意的答案。我不希望有一个明确的close
方法,并且使用with
不是一个选项,因为我的对象不像开放式播放关闭那样简单,而是保持为另一个更大的对象的成员,它在GUI中运行时使用它。
C ++具有完美的工作析构函数,可以安全地释放资源,所以我认为Python也有同意的东西。出于某种原因,情况似乎并非如此,社区中的许多人发誓反对__del__
。那么替代方案是什么?
答案 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甚至“更好”,因为它有一个垃圾收集器。