【发布时间】:2016-07-03 02:23:50
【问题描述】:
应用程序通常需要连接到其他服务(数据库、缓存、API 等)。出于理智和 DRY 的考虑,我们希望将所有这些连接保留在一个模块中,以便我们的代码库的其余部分可以共享连接。
为了减少样板,下游使用应该很简单:
# app/do_stuff.py
from .connections import AwesomeDB
db = AwesomeDB()
def get_stuff():
return db.get('stuff')
而且设置连接也应该很简单:
# app/cli.py or some other main entry point
from .connections import AwesomeDB
db = AwesomeDB()
db.init(username='stuff admin') # Or os.environ['DB_USER']
像 Django 和 Flask 这样的 Web 框架会做这样的事情,但感觉有点笨拙:
Connect to a Database in Flask, Which Approach is better? http://flask.pocoo.org/docs/0.10/tutorial/dbcon/
这样做的一个大问题是我们希望引用实际的连接对象而不是代理,因为我们希望在 iPython 和其他开发环境中保留制表符补全。
那么正确的方法(tm)是什么?经过几次迭代,这是我的想法:
#app/connections.py
from awesome_database import AwesomeDB as RealAwesomeDB
from horrible_database import HorribleDB as RealHorribleDB
class ConnectionMixin(object):
__connection = None
def __new__(cls):
cls.__connection = cls.__connection or object.__new__(cls)
return cls.__connection
def __init__(self, real=False, **kwargs):
if real:
super().__init__(**kwargs)
def init(self, **kwargs):
kwargs['real'] = True
self.__init__(**kwargs)
class AwesomeDB(ConnectionMixin, RealAwesomeDB):
pass
class HorribleDB(ConnectionMixin, RealHorribleDB):
pass
改进空间:将初始 __connection 设置为通用 ConnectionProxy 而不是 None,它会捕获所有属性访问并引发异常。
我在这里做了很多关于 SO 和各种 OSS 项目的探索,但还没有见过这样的事情。感觉非常可靠,尽管这确实意味着一堆模块将实例化连接对象作为导入时的副作用。这会在我脸上炸开吗?这种方法还有其他负面影响吗?
【问题讨论】:
标签: python design-patterns architecture database-connection