Python单例模式

3

有人可以告诉我为什么这不是单例模式吗:

class preSingleton(object):
    def __call__(self):
        return self

singleton = preSingleton()

# singleton is actually the singleton

a = singleton()
b = singleton()

print a==b  

a.var_in_a = 100
b.var_in_b = 'hello'

print a.var_in_b
print b.var_in_a

编辑:上述代码输出:

True
hello
100

非常感谢您。

第二部分

也许这样更好?

class Singleton(object):
    def __new__(cls):
        return cls

a = Singleton()
b = Singleton()

print a == b

a.var_in_a = 100
b.var_in_b = 'hello'

print a.var_in_b
print b.var_in_a

编辑:上述代码输出:

True
hello
100

再次感谢。

能否展示一下打印语句的输出结果? - Tom
1
请使用 id(a)id(b) 来检查对象的身份。请提供实际输出。 - S.Lott
6个回答

9

在Python中,单例模式其实非常简单。关键是让模块为你进行封装,而不是创建一个类。

  • 该模块只会被初始化一次
  • 该模块直到第一次被导入时才会被初始化
  • 任何尝试重新导入该模块的操作都将返回指向现有导入的指针

如果你想要假装该模块是一个类的实例,可以执行以下操作:

import some_module
class SomeClass(object):
    def __init__(self):
        self.singleton = some_module

3

因为这不是一个单例。单例必须是唯一的,而你的对象并不是。

>>> class preSingleton(object):
...     def __call__(self):
...         return self
...
>>> singleton = preSingleton()
>>> singleton2 = preSingleton()
>>> singleton
<__main__.preSingleton object at 0x00C6D410>
>>> singleton2
<__main__.preSingleton object at 0x00C6D290>

PreSingleton 不是单例,singleton 才是。你误解了代码。 - Skilldrick
不,我没有误解。它们也不是单例模式。如果你像那样运行代码两次,你会得到不同的实例,就是这样。 - unbeli
1
好的,那么任何变量都是单例。你只需要获取一个值,它总是相同的,哇,单例! - unbeli
如果你把singleton想象成一个类,那么每次实例化它时都会得到相同的对象。对我来说,这就满足了单例的含义。仅仅因为它没有使用私有构造函数、静态方法和所有那些花哨的东西来实现,并不意味着它作为一种实现方式就不合法。 - Skilldrick
@Skilldrick 我只能部分地同意。在它目前的形态下,人们只能 假装 它是一个单例。如果你清理命名空间(删除/覆盖 preSingleton),那么它可能会成为一个真正的单例,这不会引发更多相同类型的创建。 - unbeli
显示剩余2条评论

2

这是一个作为装饰器实现的简单单例模式:

def singleton(cls):
    """Decorate a class with @singleton when There Can Be Only One."""
    instance = cls()
    instance.__call__ = lambda: instance
    return instance

使用方法如下:

@singleton
class MySingleton:
    def spam(self):
        print id(self)

发生的情况是,在类定义之外,MySingleton 实际上将引用唯一存在的类实例,你将没有任何机制来创建任何新的实例。调用 MySingleton() 将简单地返回完全相同的实例。例如:

>>> MySingleton
<__main__.MySingleton instance at 0x7f474b9265a8>
>>> MySingleton()
<__main__.MySingleton instance at 0x7f474b9265a8>
>>> MySingleton() is MySingleton
True
>>> MySingleton.spam()
139944187291048
>>> MySingleton().spam()
139944187291048

在Python中实现单例类的策略就像在一月份的莫尔曼斯克卖冰淇淋一样困难。"单例"只需创建一个模块实例即可...请参考上面unholysampler的解释。 - Christophe
我不同意,使用模块有一些缺点。例如,如果您想在单例中的两个方法之间共享状态,则需要使用模块全局变量来实现,这会变得很丑陋(希望设置该变量的函数必须调用 global your_variable)。此外,我有许多用于不同目的的小型单例。将它们定义为单个模块中的几个类比所有单独的模块更好,因为它们太小而无法作为自己的模块。 - robru

2

实际上这是Borg模式。多个对象共享状态。

这并不意味着它有什么问题,对于大多数情况而言(如果不是全部),它在功能上等同于单例模式,但既然你问了……

编辑:当然,由于它们是Borg对象,每个实例使用更多的内存,因此如果您创建了大量对象,这将对资源使用产生影响。


1

我看不出有什么问题(如果它走起来像鸭子,叫起来像鸭子……)。在我看来,这看起来像是一个单例。

它与Java的单例模式(例如)的工作方式不同,因为Python使用相同的语法来调用函数和创建对象的新实例。因此,singleton() 实际上是在调用单例对象,该对象返回自身。


0

你可以使用你的类来完成这个任务:

>>> class preSingleton(object):
...     def __call__(self):
...         return self
...
>>> x = preSingleton()
>>> y = preSingleton()
>>> x == y
False

因此,可以创建多个类的实例,这违反了单例模式。


preSingleton 不是单例模式,singleton 才是。 - Skilldrick

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接