Skip to content Skip to sidebar Skip to footer

How To Initialize Singleton-derived Object Once

Possible Duplicate: Is there a simple, elegant way to define Singletons in Python? I have the following example code, in which I derive a class from a Singleton (hope it is one)

Solution 1:

My previous answer didn't work and I've deleted it. However I've found a highly rated SO answer that does. The primary differences are that it uses a Singletonmetaclass instead of a baseclass and overloads the __call__() method of its instance classes instead of their __new__() method. This gives it the control required over the creation process of instances of its singleton class instances. It would be possible to define an additional method for deleting one or more of these — say for testing purposes.

Another notable implementation detail is that the metaclass maintains a dictionary of _instances rather than something that can only hold a single value. This allows it keep track of an indefinite number of singleton instances (since it might be the metaclass of more than one since it's reusable).

Applying it to your sample code would be done something like this:

classSingleton(type):
    """Metaclass."""
    _instances = {}

    def__call__(cls, *args, **kwargs):
        if cls notin cls._instances:
            cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
        return cls._instances[cls]

classTracer(object):
    __metaclass__ = Singleton

    def__init__(self):
        print("Init")

a = Tracer()
b = Tracer()
print('a is b: {}'.format(a is b))  # same object? -> True

Output:

Init
a is b: True

Update

The syntax for specifying a metaclass varies between Python 2 and 3. For the latter you'd need to change the Tracer class definition to this:

#!/usr/bin/env python3classTracer(object, metaclass=Singleton):
    def__init__(self):
        print("Init")

Writing a something that would work in both version 2 and 3 of Python is possible, but is a little more complicated since you can't simply conditionally define it like this:

## Won't work ##if sys.version_info[0] < 3:  # Python 2?classTracer(object):
        __metaclass__ = Singleton

        def__init__(self):
            print("Init")

else:  # Python 3classTracer(object, metaclass=Singleton):  # causes SyntaxError in Python 2def__init__(self):
            print("Init")

because the definition in the else clause causes a SyntaxError in Python 2 (even though the code in the block will never actually be executed). A workaround similar to what Benjamin Peterson's six module's with_metaclass() function does and would look like this:

classTracer(Singleton("SingletonBaseClass", (object,), {})):
    def__init__(self):
        print("Init")

This dynamically creates a baseclass that inherits the desired metaclass—thereby avoiding any errors due to metaclass syntax differences between the two Python versions. (Which it does by explicitly using the defined metaclass to create the temporary baseclass.)

Solution 2:

Your __init__ is called twice, but on the same object. You have created a singleton, but Python doesn't know it is, so it initializes each object that gets created.

If you want to pursue the singleton pattern, you'll have to move your initializing code into the __new__, or into another method that your __new__ calls.

Keep in mind:

  1. Singletons are the norm in Java, but are frowned upon in Python.

  2. Singletons make your code harder to test, because they are global state carried from one test to the next.

Post a Comment for "How To Initialize Singleton-derived Object Once"