9

在 python 中使用 Singleton 模式有很多问题,虽然这个问题可能会重复已经讨论过的许多方面,但我还没有找到以下具体问题的答案。

假设我有一个类MyClass,我只想实例化一次。在 python 中,我可以在代码中执行以下操作myclass.py

class MyClass(object): 
    def foo(self):
        ....


instance = MyClass()

然后在任何其他程序中,我可以简单地引用该实例

import myclass
myclass.instance.foo()

在什么情况下这种方法就足够了?在什么情况下使用单例模式有用/强制?

4

3 回答 3

7

单例模式更多的是为了方便而不是需求。与其他语言相比,Python 与其他语言有点不同,因为它很容易在测试中模拟出单例(只是破坏全局变量!),但是在创建单例时问自己并不是一个好主意:我这样做是为了方便还是因为只有一个实例是非常必要的?未来有可能不止一个吗?

如果您创建的类实际上只构造一次,则将状态作为模块的一部分并将其方法放入模块级函数可能更有意义。如果将来有可能对一个实例的假设可能会发生变化,那么传递单例实例通常比通过全局名称引用单例要好得多。

例如,您可以通过这种方式轻松实现“单例”:

if __name__ == '__main__':
   instance = MyClass()
   doSomethingWith(instance)

在上面,“instance”是单例的,因为它只被构造一次,但是处理它的代码提供的是 instance 而不是引用module.instance,这使得在将来重用代码片段变得更容易情况,你需要不止一个MyClass

于 2013-01-30T09:08:14.773 回答
3

假设您想像 Michael Aaron Safyan 建议的那样将模块用作单例,即使该模块不是由主代码导入,您也可以通过执行以下操作(在主代码或它确实导入的模块中)使其工作直接或间接)。它所做的是将一个instance类属性初始化为一个,然后用sys.modules创建的实例替换模块对象:

class _MyClass(object):
    def foo(self):
        print 'foo()'

_MyClass.instance = _MyClass()

import sys
_ref = sys.modules[__name__]  # Reference to current module so it's not deleted
sys.modules[__name__] = _MyClass.instance

当只有一个(注册表)有意义时,我发现单例是一种实现事物“寄存器”的有用方法——例如类工厂的一组类、一组常量或一组配置信息. 在许多情况下,只需一个普通的 Python 模块就可以了,因为默认情况下,它们实际上已经是单例,因为那些已经加载的模块会缓存在sys.modules字典中。

然而,有时,类实例更可取,因为它们可以传递构造参数并具有属性——内置模块对象没有也不能拥有的东西。可以使用上面显示的技巧来解决此类限制,该技巧有效地将自定义类实例转换为模块对象。

使用类实例作为模块对象的想法来自Alex MartelliActiveState配方,名为Python 中的常量

于 2013-01-30T11:27:29.200 回答
1

在我看来,单例模式有两个方面。

  • 您需要给定服务的单一上下文,因为多个上下文没有意义。
  • 您想绝对阻止人们创建给定类型的两个对象,因为它可能会破坏您的服务

虽然第一种情况可能有一些应用程序(日志服务),但第二种情况通常是设计不佳的标志。

您应该设计您的 API,以便您的用户不必考虑这个问题。但是,如果他们挖掘您未记录的层以找到您的隐藏构造函数并出于任何原因想要使用它,他们不应该处理为阻止他们执行所需操作而创建的无用构造。

于 2013-01-30T09:12:42.463 回答