2

While I was watching some code about singleton's in python I decided to write my own.

This was my first code:

def singleton(cls):
    instance = False
    def constructor(*args,**kwargs):
        if not instance:
            instance = cls(*args,**kwargs)
        return instance
    return constructor

But when i tested it, the interpreter told me that 'instance' must be declared before being used on the if condition, finally I figured out to do it as follows:

def singleton(cls):
    cls._instance = False
    def constructor(*args,**kwargs):
        if not cls._instance:
            cls._instance = cls(*args,**kwargs)
        return cls._instance
    return constructor

and it worked as expected:

>>> @singleton
>>> class A: pass
>>> a=A()
>>> id(a)
33479456
>>> b=A()
>>> id(b)
33479456

Why the closure from the first example didn't work.

Edit: the error was

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

2 Answers 2

3

Your first closure didn't work because inside your constructor function, you assigned to instance. That makes instance a local name inside constructor, and you accessed that local name before it was assigned to.

In Python 3, you can use nonlocal instance to declare the scope of instance. In Python 2, you can't access that outer instance name as you want to.

Also, singletons are unusual in Python. Why not just instantiate your class once? Why try to trick Python into behaving differently than it does? Or create a factory function to produce the instance to use?

Sign up to request clarification or add additional context in comments.

1 Comment

A workaround would be to use an object attribute to write the value to or not to use singletons! :)
0

Closure-variables are read-only in Python, so when you attempt to assing a value to instance, Python can't do it. The error message is slightly misleading, because instance is declared, it just isn't writeable inside the closure.

6 Comments

Ah, well, just saw your update. Turns out the error message wasn't that misleading at all :-)
closure variables are not read-only, they're just awkward to modify, as the OP has found out.
I actually thought they were impossible to modify? In Python 2, is it possible in some awkward way to assign a new value to a closure variable?
@AHM You're conflating modifying an object and pointing a name. He can do instance = [] in the non-local scope, then instance.append(1) in the local scope, modifying it, without any issue. It's actually pointing the name at another object that is different.
Ah. okay, yes. I was aware of that, just not formulating myself correctly there. For a moment I thought there were some mysterious way of getting functionality like the nonlocal keyword from Python 3 in Python 2.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.