Skip to content
All Posts

Python Singletons and Metaclasses

Notes on Python singleton implementations and how metaclasses control class creation.

Ways to implement a singleton

Bind an instance to a class variable:

class Singleton(object):
_instance = None
def __new__(cls, *args):
if not isinstance(cls._instance, cls):
cls._instance = super(Singleton, cls).__new__(cls, *args)
return cls._instance

After inheritance, though, a subclass can override __new__ and lose the singleton property:

class D(Singleton):
def __new__(cls, *args):
return super(D, cls).__new__(cls, *args)

Use a decorator:

def singleton(_cls):
inst = {}
def getinstance(*args, **kwargs):
if _cls not in inst:
inst[_cls] = _cls(*args, **kwargs)
return inst[_cls]
return getinstance
@singleton
class MyClass(object):
pass

The problem is that the decorator returns a function rather than a class. You can define a class inside singleton to work around that, but it gets rather cumbersome.

Using __metaclass__ is the approach I recommend most:

class Singleton(type):
_inst = {}
def __call__(cls, *args, **kwargs):
if cls not in cls._inst:
cls._inst[cls] = super(Singleton, cls).__call__(*args)
return cls._inst[cls]
class MyClass(object):
__metaclass__ = Singleton

Metaclasses

A metaclass creates classes. You can think of it as a class factory: classes are instances of metaclasses. type is Python’s built-in metaclass, and it is its own metaclass:

>>> type(MyClass)
type
>>> type(type)
type

When Python creates MyClass, it looks for __metaclass__ in the class definition. If it finds one, it uses it to create MyClass; otherwise it uses the built-in type. If the class has parents and the current class does not define one, Python keeps looking up the inheritance chain. Only when none of the parents has __metaclass__ does it use type. If a module has a global __metaclass__ variable, every class in that module uses it.

The definition of type is:

type(object) -> the object’s type
type(name, bases, dict) -> a new type

So to define a metaclass using type, you can return an object made with the second form above, or inherit from type and override its methods.

Here, the function-generated metaclass changes attribute names to uppercase:

def update_(name, bases, dct):
attrs = ((name, value) for name, value in dct.items() if not name.startswith('__'))
uppercase_attr = {name.upper(): value for name, value in attrs}
return type(name, bases, uppercase_attr)
class Singleton(object):
__metaclass__ = update_
abc = 2
d = Singleton()
print d.ABC
# 2

The singleton metaclass implementation above uses inheritance. In contrast, the first __new__ approach ultimately calls type.__new__. Using super makes the inheritance clearer and avoids a few problems.

Here is a brief distinction: __new__ runs before __init__; it creates and returns an object. __init__ initializes that object with the arguments it receives. The implementations of these two methods and __call__ on type look like this:

def __init__(cls, what, bases=None, dict=None): # known special case of type.__init__
"""
type(object) -> the object's type
type(name, bases, dict) -> a new type
# (copied from class doc)
"""
pass
@staticmethod # known case of __new__
def __new__(S, *more): # real signature unknown; restored from __doc__
""" T.__new__(S, ...) -> a new object with type S, a subtype of T """
pass
def __call__(self, *more): # real signature unknown; restored from __doc__
""" x.__call__(...) <==> x(...) """
pass

Classes are instances of metaclasses. Linking that back to the function used to create a singleton, any of those three magic methods can be used. Here is what gets called when a metaclass uses each one:

class Basic(type):
def __new__(cls, name, bases, newattrs):
print "new: %r %r %r %r" % (cls, name, bases, newattrs)
return super(Basic, cls).__new__(cls, name, bases, newattrs)
def __call__(self, *args):
print "call: %r %r" % (self, args)
return super(Basic, self).__call__(*args)
def __init__(cls, name, bases, newattrs):
print "init: %r %r %r %r" % (cls, name, bases, newattrs)
super(Basic, cls).__init__(name, bases, dict)
class Foo:
__metaclass__ = Basic
def __init__(self, *args, **kw):
print "init: %r %r %r" % (self, args, kw)
a = Foo('a')
b = Foo('b')

The result:

new: <class ‘main.Basic’> ‘Foo’ () {‘module’: ‘main’, ‘metaclass’: <class ‘main.Basic’>, ‘init’: <function init at 0x106fd5320>}
init: <class ‘main.Foo’> ‘Foo’ () {‘module’: ‘main’, ‘metaclass’: <class ‘main.Basic’>, ‘init’: <function init at 0x106fd5320>}
call: <class ‘main.Foo’> (‘a’,)
init: <main.Foo object at 0x106fee990> (‘a’,) {}
call: <class ‘main.Foo’> (‘b’,)
init: <main.Foo object at 0x106feea50> (‘b’,) {}

The metaclass’s __init__ and __new__ run only once, when Foo is created. Each time a Foo instance is created, the metaclass’s __call__ runs.


Originally published on SegmentFault.