在Python中的单例模式

6

我是一名Python新手,正在尝试通过检查和创建Python设计模式的示例来学习这种语言。

我对Singleton Pattern的经典实现感到困惑。大多数文章都提到以下实现方式作为经典:

class Singleton(object):
    name = None

    @staticmethod
    def instance():
        if '_instance' not in Singleton.__dict__:
            Singleton._instance = Singleton()

        return Singleton._instance


s1 = Singleton().instance();
s2 = Singleton().instance();

assert s1 is s2

但我对这个实现并不完全信服,因为我们没有限制用户创建单例类的多个对象,我仍然可以通过调用Singleton()来创建该类的一个实例。在Java中,我们通过将类的构造函数设置为私有来防止这种情况。

另一种实现方式是:

class Singleton(object):
    _instances = {}

    def __new__(class, *args, **kwargs):
        if class not in class._instances:
            instance = super().__new__(class)
            class.__instances[class] = instance
        return class._instances[class]

这让我感到非常困惑。有人能解释一下这是如何工作的吗?

1
重写__new__()方法并始终返回相同的实例。 - kindall
1
可能是在Python中创建单例模式的重复问题。 - Stefan Papp
单例模式在Python中并不是非常“经典”。实际上,它并不是必需的。 - juanpa.arrivillaga
那么,您如何为仅需要一个对象的日志记录等创建类? - ThinkGeek
1
在Python中,如果你只需要一个实例,那么你只需要创建一个实例。简单! - kindall
显示剩余8条评论
1个回答

13

首先要记住的是,Python不是Java,它不像其他语言那样有很多限制。正如Guido所说的:"我们都是成年人"。实际上,Python几乎没有什么可以阻止你做任何事情。解决方案是"不要这么做"。

然而,有几种方法可以实现单例。另一种更具用户友好性的方式是使用类似于类实例化的工厂函数。以下是一个示例。

class _Singleton:
    _instance = None

    def hello(self):
        print("Hello!")


def Singleton():
    if _Singleton._instance is None:
        _Singleton._instance = _Singleton()
    return _Singleton._instance



s1 = Singleton()
s2 = Singleton()

assert s1 is s2

1
我仍然可以执行s1 = _Singleton()和s2 = _Singleton()。我同意你的观点,我们是成年人,不应该做错事。但我很惊讶在Python中我们没有强制执行这些规则,太疯狂了。 - ThinkGeek
真的,但使用元类的更“高级”方法可以解决这个问题。但是既然你似乎对这门语言还很陌生,我提供了一个更简单的例子。这意味着你必须自己编写代码,明确地表达出来。 - Keith
我添加了另一种基于基类的实现,这让我感到非常困惑(也许是因为Java注入了我的血液)。 - ThinkGeek
@LokeshAgrawal 这只是重写构造函数__new__,并简单地创建一个实例缓存作为类变量(在Java术语中称为“静态变量”)。 - juanpa.arrivillaga
这一行代码:instance = super().new(class) 让我感到害怕,看起来像是无限递归。 - ThinkGeek
2
请忽略我之前的评论,在了解了__new__和__init__之后,我知道为什么这行代码在那里了。感谢您在这里的帮助。 - ThinkGeek

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