The general syntax

The call to the built-in type() class can be used as a dynamic equivalent of the class statement. The following is an example of a class definition with the type() call: 

def method(self): 
    return 1 
 
MyClass = type('MyClass', (object,), {'method': method}) 

This is equivalent to the explicit definition of the class with the class keyword:

class MyClass: 
    def method(self): 
        return 1

Every class that's created with the class statement implicitly uses type as its metaclass. This default behavior can be changed by providing the metaclass keyword argument to the class statement, as follows:

class ClassWithAMetaclass(metaclass=type): 
    pass 

The value that's provided as a metaclass argument is usually another class object, but it can be any other callable that accepts the same arguments as the type class and is expected to return another class object. The call signature is type(name, bases, namespace) and the meaning of the arguments are as follows:

One way of thinking about metaclasses is the __new__() method, but at a higher level of class definition.

Despite the fact that functions that explicitly call type() can be used in place of metaclasses, the usual approach is to use a different class that inherits from type for this purpose. The common template for a metaclass is as follows:

class Metaclass(type): 
    def __new__(mcs, name, bases, namespace): 
        return super().__new__(mcs, name, bases, namespace) 
 
    @classmethod 
    def __prepare__(mcs, name, bases, **kwargs): 
        return super().__prepare__(name, bases, **kwargs) 
 
    def __init__(cls, name, bases, namespace, **kwargs): 
        super().__init__(name, bases, namespace) 
 
    def __call__(cls, *args, **kwargs): 
        return super().__call__(*args, **kwargs) 

The name, bases, and namespace arguments have the same meaning as in the type() call we explained earlier, but each of these four methods can have the following different purposes:

Each of the preceding methods can accept additional extra keyword arguments, all of which are represented by **kwargs. These arguments can be passed to the metaclass object using extra keyword arguments in the class definition in the form of the following code:

class Klass(metaclass=Metaclass, extra="value"): 
    pass 

This amount of information can be overwhelming at the beginning without proper examples, so let's trace the creation of metaclasses, classes, and instances with some print() calls:

class RevealingMeta(type): 
    def __new__(mcs, name, bases, namespace, **kwargs): 
        print(mcs, "__new__ called") 
        return super().__new__(mcs, name, bases, namespace) 
 
    @classmethod 
    def __prepare__(mcs, name, bases, **kwargs): 
        print(mcs, "__prepare__ called") 
        return super().__prepare__(name, bases, **kwargs) 
 
    def __init__(cls, name, bases, namespace, **kwargs): 
        print(cls, "__init__ called") 
        super().__init__(name, bases, namespace) 
 
    def __call__(cls, *args, **kwargs): 
        print(cls, "__call__ called") 
        return super().__call__(*args, **kwargs) 

Using RevealingMeta as a metaclass to create a new class definition will give the following output in the Python interactive session:

>>> class RevealingClass(metaclass=RevealingMeta):
...     def __new__(cls):
...         print(cls, "__new__ called")
...         return super().__new__(cls)
...     def __init__(self):
...         print(self, "__init__ called")
...         super().__init__()
... 
<class 'RevealingMeta'> __prepare__ called
<class 'RevealingMeta'> __new__ called
<class 'RevealingClass'> __init__ called
>>> instance = RevealingClass()
<class 'RevealingClass'> __call__ called <class 'RevealingClass'> __new__ called <RevealingClass object at 0x1032b9fd0> __init__ called

Let's take a look at the new Python 3 syntax for metaclasses.