【问题标题】:Python singleton / object instantiationPython单例/对象实例化
【发布时间】:2015-09-09 05:04:44
【问题描述】:

我正在学习 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__']

有可能做我正在尝试的事情吗?如果没有,还有其他方法吗?

欢迎提出任何建议。

干杯。

【问题讨论】:

  • 除了一个有趣的学习练习,你有这个 Singleton 的用例吗?有时单例可能比这简单得多。 Singleton 设计模式——在一定程度上——是一种 Smalltalk/C++/Java 主义,在 Python 中并不经常需要。

标签: python singleton


【解决方案1】:

分配给一个参数或任何其他局部变量(barename)永远不可能在函数之外产生任何影响;这适用于您的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(又名单态)而不是您选择的汉兰达(又名单例),但这与您所询问的问题不同;-)。

【讨论】:

  • 嗯,所以在这里赞助他的(伟大的)生物 :) 我同意,当然
  • 谢谢!我想我对 init 方法的了解并没有我想象的那么多;我被影响对象的 self.name 愚弄了,但我想这有点 Python 魔术?问题更多是关于理解 Python 而不是使用单例模式,但无论如何我都会查看 Borg 链接:)
  • self.name 是 QUALIFIED 名称,而不是 BARENAME:分配给一个barename 和分配给一个限定名可能是完全不同的操作——我在相应的章节中使用了相当多的篇幅的“Python in a Nutshell”,在这里重复所有内容太多了,所以我建议您阅读(可能来自网络上的众多盗版副本之一:作为作者,我对它们不满意,但肯定有巨大的数字!-)
  • 也许我遗漏了什么,但每个__instance 不应该是cls.__instancetype 应该是object 吗??
【解决方案2】:

Bruce Eckel's code snippet from Design Pattern: I'm confused on how it works

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>
'''

【讨论】:

【解决方案3】:

来自Singleton Pattern (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()

【讨论】:

  • 你单例为什么要继承“类型”?什么是类型?为什么不反对?
  • 这种实现Singleton的方式调用了两次init,这让我很头疼,将修改后的变量覆盖回原来的初始化。
【解决方案4】:

这是您可以制作的最基本的单例。它使用class method 来检查单例是否已创建,如果没有则创建一个新的。有更高级的方法可以解决这个问题,例如覆盖__new__ method

class Singleton:
    instance = None

    @classmethod
    def get(cls):
        if cls.instance is None:
            cls.instance = cls()
        return cls.instance

    def __init__(self):
        self.x = 5       # or whatever you want to do

sing = Singleton.get()
print sing.x  # prints 5

至于你的代码为什么会失败,有几个原因。首先,在调用__init__ 时,已经创建了一个新对象,这违背了单例模式的目的。其次,当你说self = __instance时,它只是重置了局部变量self;这类似于说

def f(x):
  x = 7    # changes the value of our local variable

y = 5
f(y)
print y   # this is still 5

由于 Python 中的变量是按值传递而不是按引用传递的,因此您不能说 self = blah 并让它以您想要的方式有意义。上面的 Singleton 类更符合您的要求,除非您想花哨并考虑覆盖 __new__ 运算符。

【讨论】:

【解决方案5】:
self = _instance

这不会做你期望它做的事情。了解 Python 如何处理名称。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多