Timur Izhbulatov — Independent Electronic Music

Singleton in Python

Wed, 17 Dec 2008 01:02:00 in Tech stuff | permalink

pattern python singleton

Updated 2009-03-03. Arbitrary constructor arguments (Mark's suggestion).

Updated 2008-12-30. Thread-safety.

A recent discussion has drawn my attention again to the use of the Singleton pattern in Python. Here's how and why I do this.

Why?

I don't like the module-is-a-singleton way, when you just keep your single instance as module global, because in terms of API you don't use the class to access its instance. In other words, it doesn't look like you're creating an instance.

Also, with this approach instances are created when the corresponding module is imported, which is not always desirable.

I want to instantiate classes as usual when I need this, but have one instance per class.

How?

In Python you can customize object creation using the __new__() method. Consider the following simple example:

class Singleton(object):
    __instance__ = None

    def __new__(cls):
        if cls.__instance__ is None:
            cls.__instance__ = super(Singleton, cls).__new__(cls)
        return cls.__instance__

    def __init__(self):
        print '__init__:', self

s1 = Singleton()
s2 = Singleton()
assert s1
assert s2
assert s1 is s2
In this example the only Singleton instance is stored in the __instance__ class attribute.

However, there's a problem in this snippet. Note that the __init__() method is called on every instantiation. This is normal behaviour of types in Python. When you instantiate a class, __new__() and __init__() are called internally. But I want the signle instance to be created and initialized only once.

As far as I know, the only way to achieve this is metaclasses. In metaclass you can define what happens when you call its instances (which are also classes):

class SingletonType(type):
    def __call__(cls):
        if getattr(cls, '__instance__', None) is None:
            instance = cls.__new__(cls)
            instance.__init__()
            cls.__instance__ = instance
        return cls.__instance__

class Singleton(object):
    __metaclass__ = SingletonType

    def __init__(self):
        print '__init__:', self


class OtherSingleton(object):
    __metaclass__ = SingletonType

    def __init__(self):
        print 'OtherSingleton __init__:', self


s1 = Singleton()
s2 = Singleton()
assert s1
assert s2
assert s1 is s2

os1 = OtherSingleton()
os2 = OtherSingleton()
assert os1
assert os2
assert os1 is os2
In this new example we define the __call__ method in metaclass where __new__() and __init__() are called manually and only once.

Another benefit is that with the SingletonType metaclass we can make any existing class a singleton by simply adding the __metaclass__ attribute.

Finally, the above example can be easily enhanced to maintain thread-safety by adding proper locking:

import threading
import thread

class SingletonType(type):
    def __new__(mcls, name, bases, namespace):
        # Allocate lock, if not already allocated manually
        namespace.setdefault('__lock__', threading.RLock())
        # Since we already using __new__, we can also initialize the
        # __instance__ attribute here
        namespace.setdefault('__instance__', None)
        return super(SingletonType, mcls).__new__(mcls, name, bases, namespace)

    def __call__(cls):
        cls.__lock__.acquire()
        try:
            # __instance__ is now always initialized, so no need to use default
            # value
            if cls.__instance__ is None:
                instance = cls.__new__(cls)
                instance.__init__()
                cls.__instance__ = instance
        finally:
            cls.__lock__.release()
        return cls.__instance__


class Singleton(object):
    __metaclass__ = SingletonType

    def __init__(self):
        print '__init__:', self


class OtherSingleton(object):
    __metaclass__ = SingletonType

    def __init__(self):
        print 'OtherSingleton __init__:', self


s1 = Singleton()
s2 = Singleton()
assert s1
assert s2
assert s1 is s2

os1 = OtherSingleton()
os2 = OtherSingleton()
assert os1
assert os2
assert os1 is os2

In this enhanced example a separate reentrant lock object (wich locks only if already acquired by another thread) is allocated for each Singleton class (Singleton and OtherSingleton). This happens at module import time because metaclasses in Python are applied right after class definition is closed.

Finally, in a more real world example it would be desirable to have constructors which accept arbitrary positional and keyword arguments. Thus, we can change the corresponding methods' signatures as Mark suggested in his comment:

import threading
import thread

class SingletonType(type):
    def __new__(mcls, name, bases, namespace):
        namespace.setdefault('__lock__', threading.RLock())
        namespace.setdefault('__instance__', None)
        return super(SingletonType, mcls).__new__(mcls, name, bases, namespace)

    def __call__(cls, *args, **kw):
        cls.__lock__.acquire()
        try:
            if cls.__instance__ is None:
                instance = cls.__new__(cls, *args, **kw)
                instance.__init__(*args, **kw)
                cls.__instance__ = instance
        finally:
            cls.__lock__.release()
        return cls.__instance__


class Singleton(object):
    __metaclass__ = SingletonType

    def __init__(self, a, b=None):
        print '__init__:', self


class OtherSingleton(object):
    __metaclass__ = SingletonType

    def __init__(self, a, b=None):
        print 'OtherSingleton __init__:', self


s1 = Singleton(0, b=1)
s2 = Singleton(b=3)
assert s1
assert s2
assert s1 is s2

os1 = OtherSingleton(4)
os2 = OtherSingleton(6, b=7)
assert os1
assert os2
assert os1 is os2

Now the SingletonType is more usable as it passes through all arguments to constructor.