Skip to content
Back to 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.

Copyright notice

Unless otherwise stated, quietin owns the copyright in all articles. All rights reserved. Except as permitted by law or with prior written permission, reproduction or republication, in whole or in part, is prohibited. Permitted quotations must credit the author and link to the original article.