Python 单例 / 对象实例化

6 投票
5 回答
15086 浏览
提问于 2025-04-15 14:00

我正在学习Python,最近尝试实现一个单例类作为练习。我的代码如下:

_Singleton__instance = None

class Singleton:
    def __init__(self):
        global __instance
        if __instance == None:           
            self.name = "The one"
            __instance = self
        else:
            self = __instance

这个代码部分是可以工作的,但self = __instance这一部分似乎出现了问题。我附上了一些解释器的输出,以便展示(上面的代码保存在singleton.py文件中):

>>> import singleton
>>> x = singleton.Singleton()
>>> x.name
'The one'
>>> singleton._Singleton__instance.name
'The one'
>>> y = singleton.Singleton()
>>> y.name
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: Singleton instance has no attribute 'name'
>>> type(y)
<type 'instance'>
>>> dir(y)
['__doc__', '__init__', '__module__']

我想做的事情有可能实现吗?如果不行,还有其他方法可以做到吗?

欢迎任何建议。

谢谢。

5 个回答

4

来自 单例模式 (Python):

class Singleton(type):
    def __init__(self, name, bases, dict):
        super(Singleton, self).__init__(name, bases, dict)
        self.instance = None

    def __call__(self, *args, **kw):
        if self.instance is None:
            self.instance = super(Singleton, self).__call__(*args, **kw)

        return self.instance

class MyClass(object):
    __metaclass__ = Singleton

print MyClass()
print MyClass()
6

这是一个关于设计模式的讨论,提到了Bruce Eckel的代码片段。提问者对这个代码是怎么工作的感到困惑。

class Borg:
  _shared_state = {}
  def __init__(self):
    self.__dict__ = self._shared_state

class MySingleton(Borg):
  def __init__(self, arg):
    Borg.__init__(self)
    self.val = arg
  def __str__(self): return self.val

x = MySingleton('sausage')
print x
y = MySingleton('eggs')
print y
z = MySingleton('spam')
print z
print x
print y
print ´x´
print ´y´
print ´z´
output = '''
sausage
eggs
spam
spam
spam
<__main__. MySingleton instance at 0079EF2C>
<__main__. MySingleton instance at 0079E10C>
<__main__. MySingleton instance at 00798F9C>
'''
22

给一个参数或者其他局部变量(我们叫它“变量名”)赋值,永远不会对函数外部产生任何影响。这也适用于你的 self = whatever,就像对任何其他参数或局部变量的赋值一样。

相反,你应该重写 __new__ 方法:

class Singleton(object):

    __instance = None

    def __new__(cls):
        if cls.__instance == None:
            cls.__instance = object.__new__(cls)
            cls.__instance.name = "The one"
        return cls.__instance

我在这里做了其他改进,比如去掉全局变量、旧式类等等。

其实,使用 Borg(也叫单态模式)要比你选择的单例模式(Highlander)要好得多,但这和你问的问题是不同的事情;-)。

撰写回答