Python Language Metaclasses Basic Metaclasses


When type is called with three arguments it behaves as the (meta)class it is, and creates a new instance, ie. it produces a new class/type.

Dummy = type('OtherDummy', (), dict(x=1))
Dummy.__class__              # <type 'type'> 
Dummy().__class__.__class__  # <type 'type'> 

It is possible to subclass type to create an custom metaclass.

class mytype(type):
    def __init__(cls, name, bases, dict):
        # call the base initializer
        type.__init__(cls, name, bases, dict)

        # perform custom initialization...
        cls.__custom_attribute__ = 2

Now, we have a new custom mytype metaclass which can be used to create classes in the same manner as type.

MyDummy = mytype('MyDummy', (), dict(x=2))
MyDummy.__class__              # <class '__main__.mytype'>
MyDummy().__class__.__class__  # <class '__main__.mytype'>
MyDummy.__custom_attribute__   # 2

When we create a new class using the class keyword the metaclass is by default chosen based on upon the baseclasses.

>>> class Foo(object):
...     pass

>>> type(Foo)

In the above example the only baseclass is object so our metaclass will be the type of object, which is type. It is possible override the default, however it depends on whether we use Python 2 or Python 3:

Python 2.x2.7

A special class-level attribute __metaclass__ can be used to specify the metaclass.

class MyDummy(object):
    __metaclass__ = mytype
type(MyDummy)  # <class '__main__.mytype'>
Python 3.x3.0

A special metaclass keyword argument specify the metaclass.

class MyDummy(metaclass=mytype):
type(MyDummy)  # <class '__main__.mytype'>

Any keyword arguments (except metaclass) in the class declaration will be passed to the metaclass. Thus class MyDummy(metaclass=mytype, x=2) will pass x=2 as a keyword argument to the mytype constructor.

Read this in-depth description of python meta-classes for more details.