7

所以在 python 中对单例有很多仇恨。我通常认为拥有单例通常不好,但是有副作用的东西呢,比如使用/查询数据库?当我可以重新使用已经建立的现有连接时,为什么我要为每个简单的查询创建一个新实例?什么是pythonic方法/替代方法?

谢谢!

4

2 回答 2

7

通常,您有某种对象表示使用数据库的事物(例如 的实例MyWebServer),并且您将数据库连接设为该对象的成员。

如果您将所有逻辑都放在某种函数中,请将连接设为该函数的本地连接。(这在许多其他语言中并不常见,但在 Python 中,通常有很好的方法将多阶段有状态工作封装在单个生成器函数中。)

如果您将所有数据库内容分散在各处,则只需使用全局变量而不是单例。是的,全局变量很糟糕,但单例同样糟糕,而且更复杂。在少数情况下它们很有用,但非常罕见。(这对于其他语言不一定如此,但对于 Python 来说是这样。)摆脱全局的方法是重新思考你的设计。您很有可能将模块有效地用作(单例)对象,如果您仔细考虑,您可能会想出一个好的类或函数来包装它。


显然,只是将所有全局变量移动到类属性中,而@classmethods 只是在不同的命名空间下为您提供全局变量。但是将它们移动到实例属性和方法中是另一回事。这给了你一个你可以传递的对象——如果有必要,一个你可以拥有 2 个(或者在某些情况下甚至可能是 0 个)的对象,附加一个锁,序列化等。

在许多类型的应用程序中,你最终还是会得到某个东西的单个实例——每个 Qt GUI 应用程序都有一个MyQApplication,几乎每个 Web 服务器都有一个MyWebServer,等等。不管你怎么称呼它,这实际上是一个单例或全球。如果您愿意,您可以将所有内容移到该上帝对象的属性中。

但仅仅因为你可以这样做并不意味着你应该这样做。您仍然拥有每个模块中的函数参数、局部变量、全局变量、具有自己的实例属性的其他(非巨石)类等,您应该使用适合每个值的任何内容。

例如,假设您为每个连接到您的新客户端MyWebServer创建一个新实例。ClientConnection您可以让连接MyWebServer.instance.db.execute在他们想要执行 SQL 查询时写入……但您也可以只传递self.dbClientConnection构造函数,然后每个连接就执行self.db.execute. 那么,哪一个更好呢?好吧,如果你用后一种方式来做,它会让你的代码更容易扩展和重构。如果您想在 4 个数据库之间进行负载平衡,您只需要在一个地方(MyWebServer初始化每个ClientConnection)而不是 100 个(每次ClientConnection访问数据库)更改代码。如果您想将您的单体 Web 应用程序转换为 WSGI 容器,您无需更改任何ClientConnection代码,除了构造函数。等等。

于 2013-04-11T20:56:33.790 回答
1

如果您使用的是面向对象的方法,那么abamet 将数据库连接参数附加为类属性的建议对我来说很有意义。然后,该类可以建立一个单一的数据库连接,该类的所有方法都称为self.db_connection,例如。

如果您不使用面向对象的方法,则单独的数据库连接模块可以提供功能样式的等价物。使用一个模块来建立数据库连接,然后在任何你想使用它的地方简单地导入那个模块。例如,您的代码可以将连接称为db.connection。由于模块实际上是单例,并且模块代码仅在第一次导入时运行,因此您每次都将重复使用相同的数据库连接。

于 2013-04-11T23:34:47.577 回答