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._instanceAfter 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
@singletonclass MyClass(object): passThe 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__ = SingletonMetaclasses
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)typeWhen 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# 2The 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(...) """ passClasses 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.