在多个Python模块中共享数据库连接的正确方法
我想在多个Python模块之间共享一个数据库对象。
举个相关的例子,我创建了一个叫global.py的文件:
DOCS_ROOT="c:\docs" ## as an example
SOLR_BASE="http://localhost:8636/solr/"
任何需要这个对象的其他模块都可以这样做:
from globl import DOCS_ROOT
抛开这个例子,我想做同样的事情,分享数据库连接对象,让它们在多个模块之间共享。
import MySQLdb
conn = MySQLdb.connect (host="localhost"...)
cursor = conn.cursor()
我在解释器上试过这个:
from globl import cursor
看起来是可以的。但我怀疑这会导致每次从这个模块导入时,都会执行同一个模块。所以这样做算是正确的吗?
3 个回答
我觉得Daniel已经回答了这个问题,不过我想对你想分享的游标对象再补充几句。
一般来说,直接分享游标对象并不是个好主意。当然,这要看你的程序具体是做什么的,但作为一个通用的解决方案,我建议你把这个游标对象隐藏在一个“工厂”里面,这个工厂负责生成游标。简单来说,你可以创建一个方法,比如cursor()
或者get_cursor()
,而不是把游标做成一个全局变量。这样做的主要好处(但不是唯一的好处)是你可以在这个“工厂”后面隐藏更复杂的逻辑——比如连接池、在连接断开时自动重连等等。即使你现在不需要这些功能,如果你现在开始使用这种方法,以后添加这些功能也会变得非常简单,而目前你可以把这个函数的实现保持得很简单,比如return _cursor
。
对了,模块本身还是只会被导入一次。
即使导入的代码不会多次运行,这种做法也绝对不对。
你应该把获取连接或游标的过程放在一个函数里。然后你可以用一种叫做 单例模式 或 对象池模式 来实现这个函数。
所以大概是这样的:
db.py:
_connection = None
def get_connection():
global _connection
if not _connection:
_connection = MySQLdb.connect(host="localhost"...)
return _connection
# List of stuff accessible to importers of this module. Just in case
__all__ = [ 'getConnection' ]
## Edit: actually you can still refer to db._connection
## if you know that's the name of the variable.
## It's just left out from enumeration if you inspect the module
someothermodule.py:
import db
conn = db.get_connection() # This will always return the same object
顺便说一下,根据你正在做的事情,分享你的连接对象可能不是个好主意,可能每次需要时创建一个新的连接会更好。
但这就是你想写一个 get_connection()
方法的原因,它可以帮助你在代码的其他部分避免这些问题。
你想错了。代码只会执行一次——后面的导入只是通过 sys.modules
来引用这个模块,而不会重新运行它。
(注意,只要你总是用相同的路径来导入模块,这种情况就成立。如果你在一个地方用 from globl import cursor
,而在另一个地方用 from my.fullyqualified.project.global import cursor
,那么你可能会发现代码被重新执行了。)
补充说明:正如 S.Lott 在评论中提到的,这是一种处理全局对象的很好方法。