python中的单例,闭包在decorator中不起作用

python中的单例,闭包在decorator中不起作用,python,singleton,closures,decorator,Python,Singleton,Closures,Decorator,当我在看一些关于python中singleton的代码时,我决定自己写 这是我的第一个代码: def singleton(cls): instance = False def constructor(*args,**kwargs): if not instance: instance = cls(*args,**kwargs) return instance return constructor 但是当我测试它时,

当我在看一些关于python中singleton的代码时,我决定自己写

这是我的第一个代码:

def singleton(cls):
    instance = False
    def constructor(*args,**kwargs):
        if not instance:
            instance = cls(*args,**kwargs)
        return instance
    return constructor
但是当我测试它时,解释器告诉我在if条件下使用之前必须声明“instance”,最后我决定按如下方式执行:

def singleton(cls):
    cls._instance = False
    def constructor(*args,**kwargs):
        if not cls._instance:
            cls._instance = cls(*args,**kwargs)
        return cls._instance
    return constructor
它果然起了作用:

>>> @singleton
>>> class A: pass
>>> a=A()
>>> id(a)
33479456
>>> b=A()
>>> id(b)
33479456
为什么第一个例子中的闭包不起作用

编辑:错误为

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "singleton.py", line 4, in constructor
    if not instance:
UnboundLocalError: local variable 'instance' referenced before assignment
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
构造函数中第4行的文件“singleton.py”
如果没有,请举例说明:
UnboundLocalError:赋值前引用的局部变量“实例”

在Python中,闭包变量是只读的,所以当您试图将值分配给实例时,Python无法做到这一点。错误消息有点误导性,因为声明了实例,它只是在闭包中不可写。

您的第一个闭包不起作用,因为在
构造函数中,您分配给
实例
。这使得
实例
成为
构造函数
中的本地名称,并且您在将该本地名称分配给之前访问了该名称

在Python3中,可以使用
非本地实例
来声明
实例
的范围。在Python2中,您不能按照自己的意愿访问外部
实例
名称


此外,单例在Python中是不常见的。为什么不只实例化一次类呢?为什么要试图欺骗Python,使其行为与实际不同?或者创建一个工厂函数来生成要使用的实例?

啊,刚刚看到了您的更新。事实证明,错误消息一点也不误导:-)闭包变量不是只读的,正如OP所发现的那样,它们很难修改。我真的认为它们不可能修改吗?在Python2中,是否有可能以某种尴尬的方式为闭包变量指定一个新值?@AHM您将修改一个对象和指向一个名称混为一谈。他可以在非本地范围内执行
instance=[]
,然后在本地范围内执行
instance.append(1)
,对其进行修改,而不会出现任何问题。它实际上是把名字指向另一个不同的物体。好的,是的。我意识到了这一点,只是没有正确地表达自己。有一段时间,我认为有一种神秘的方法可以从Python 2中的Python 3中获取非本地关键字之类的功能。一种解决方法是使用object属性将值写入或不使用Singleton!:)另见和