5

I'm using the following code to instantiate a singleton in python:

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

    def __call__(cls, *args, **kwargs):
        if cls.instance is None:
            if DEBUG:
                print("Creating NEW Orchestrator instance")
        else:
            if DEBUG:
                print("Using EXISTING Orchestrator instance")

            cls.instance = super(Singleton, cls).__call__(*args, **kwargs)

        return cls.instance

The init looks like this:

def __init__(self, arg=None):
    ...

When I instantiate the object it doesn't seem to accept the argument:

Obj = Object("parameter")

arg does not equal "parameter". It is None.

I thought this was the purpose in passing *args to the call. How would I pass an argument upon first instantiating a singleton?

8
  • 3
    Please include the full definition for your Object class. I am assuming this is using Singleton as its metaclass? Commented Jun 19, 2013 at 23:03
  • 1
    Don't you usually do this stuff in __new__, not __init__? Commented Jun 19, 2013 at 23:07
  • 1
    (Trivial note) It looks like there currently is a formatting / indentation issue inside your __call__ method -- the first else statement and its block should probably be "outdented" one level. Commented Jun 19, 2013 at 23:07
  • 1
    if debug: ... else: if debug: ... - what? Commented Jun 19, 2013 at 23:10
  • Surely if a singleton contructor takes arguments, it's not a singleton... Commented Jun 19, 2013 at 23:12

2 Answers 2

3

With your current Singleton class the following seems to work fine on Python 3.x (which I am assuming you are using based on the print function.

class Object(metaclass=Singleton):
    def __init__(self, arg=None):
        print("creating instance with arg:", arg)

For example:

>>> Object("parameter")
creating NEW Orchestrator instance
creating instance with arg: parameter
<__main__.Object object at 0x7f45f9ce8910>
>>> Object("foobar")   # returns the same instance as the above call
<__main__.Object object at 0x7f45f9ce8910>

Edit: You can do the same sort of thing on Python 2.x, the syntax for specifying the metaclass is just a little bit different:

class Object(object):
    __metaclass__ = Singleton
    def __init__(self, arg=None):
        print("creating instance with arg:", arg)
Sign up to request clarification or add additional context in comments.

4 Comments

Unfortunately, I'm not using 3. I prefer the print so I import from future.
See my edit, you can do the same sort of thing on Python 2.x.
Your edit is how I was originally performing it. Declaring metaclass=None as the default parameter did not work for me. It results in a syntax error on the assignment operator.
Ok. I just tried it again. It works. I do not know what caused my original error. I'll check my git log to see what else I've changed since then that could have been the issue. Thank you.
2

Better use it like this :

class Singleton(type):
    def __init__(cls,name,bases,dic):
        super(Singleton,cls).__init__(name,bases,dic)
        cls.instance=None
    def __call__(cls,*args,**kw):
        if cls.instance is None:
            cls.instance=super(Singleton,cls).__call__(*args,**kw)
        return cls.instance

class Object(object):
    __metaclass__ = Singleton
    def __init__(self, a=None):
        print a 

c = Object("parameter")

I suppose...

Note: This works under Python 2.7.4

2 Comments

I noted that the above does in fact work however it fails when using a default parameter. That is what I don't understand.
I changed def __init__(self, a): to def __init__(self, a=None): and I don't see where it fails. As far as I tested, this behaves as expected.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.