A metaclass is most commonly used as a class-factory. When you create an object by calling the class, Python creates a new class (when it executes the 'class' statement) by calling the metaclass. Combined with the normal __init__ and __new__ methods, metaclasses therefore allow you to do 'extra things' when creating a class, like registering the new class with some registry or replace the class with something else entirely.
When the class statement is executed, Python first executes the body of the class statement as a normal block of code. The resulting namespace (a dict) holds the attributes of the class-to-be. The metaclass is determined by looking at the baseclasses of the class-to-be (metaclasses are inherited), at the __metaclass__ attribute of the class-to-be (if any) or the __metaclass__ global variable. The metaclass is then called with the name, bases and attributes of the class to instantiate it.
def make_hook(f):"""Decorator to turn 'foo' method into '__foo__'"""
f.is_hook =1return f
classMyType(type):
def __new__(mcls, name, bases, attrs):if name.startswith('None'):return None
# Go over attributes and see if they should be renamed.
newattrs ={}for attrname, attrvalue in attrs.iteritems():ifgetattr(attrvalue,'is_hook',0):
newattrs['__%s__'% attrname]= attrvalue
else:
newattrs[attrname]= attrvalue
returnsuper(MyType, mcls).__new__(mcls, name, bases, newattrs)
def __init__(self, name, bases, attrs):super(MyType, self).__init__(name, bases, attrs)
# classregistry.register(self, self.interfaces)
print "Would register class %s now."% self
def __add__(self, other):classAutoClass(self, other):
pass
return AutoClass
# Alternatively, to autogenerate the classname as well as the class:
# returntype(self.__name__ + other.__name__,(self, other),{})
def unregister(self):
# classregistry.unregister(self)
print "Would unregister class %s now."% self
classMyObject:
__metaclass__ = MyType
classNoneSample(MyObject):
pass
# Will print "NoneType None"
print type(NoneSample),repr(NoneSample)classExample(MyObject):
def __init__(self, value):
self.value = value
@make_hook
def add(self, other):return self.__class__(self.value + other.value)
# Will unregister the classExample.unregister()
inst =Example(10)
# Will fail with an AttributeError
#inst.unregister()
print inst + inst
classSibling(MyObject):
pass
ExampleSibling = Example + Sibling
# ExampleSibling is now a subclass of both Example and Sibling(with no
# content of its own) although it will believe it's called 'AutoClass'
print ExampleSibling
print ExampleSibling.__mro__