A Metaclass is the class of a class. Whenever an instance of a class (object) is created, the way that the object behaves is defined by the Class. A Metaclass defines the behavior of the Class itself.
Use of Metaclass in Python
The reason behind the use of Metaclasses is that Python Classes are Objects themselves. Since Classes are Objects, we can do various operations on it, such as assigning it to a variable, copying, etc.
And since they are objects, we can create them dynamically, as we can do for any other object.
To understand the concept of Metaclasses better, we first look at how Python defines Classes. The language defines everything as an object, whether it be an int
, a string
, or anything else.
To look at the type of any Python object, if you remember, we use the type
function.
>>> print(type(123))
<class 'int'>
>>> print(type([1, 2, 3]))
<class 'list'>
>>> class A():
... def __init__(self):
... pass
...
>>> a = A()
>>> print(type(a))
<class '__main__.A'>
It returns a class
for each case, as we can observe. But to see how Python defines the class itself, we simply look at its type.
>>> print(type(type(123))
<class 'type'>
>>> print(type(A))
<class 'type'>
As you can see, the type(class
) is the class type
! So it turns out that the class is defined by a class itself? What is this phenomenon?
This is the concept of a metaclass, which serves to define other classes. Basically, it is a class factory, from which other classes such as int
s and str
s can be defined.

type
is the metaclass which the language uses to create an object. (which is why every object has a type)
And because type
is a metaclass, we can create other classes from it.
Creating Classes Dynamically
We can create classes dynamically by instantiation from the type constructor: type(name, bases, attr)
- name -> name of the Class
- bases -> classes from which the new class inherits from
- attr -> dictionary of attributes + methods contained within the class
>>> Animal = type('Animal', (), dict(__init__ = lambda self: None, worth = lambda self, value: value))
This is the same as:
class Animal():
def __init__(self):
pass
def worth(self, value):
return value
The first bit of code is much easier to write as compared to the second. Writing the class body even during dynamic declaration doesn’t provide much flexibility.
Therefore, Metaclasses provide a powerful and easy way of dynamically creating new classes.
Creating custom Metaclasses
To create our own metaclass, we need to inherit the existing `type` metaclass and override some special methods:
- __new__() -> This is called before
__init__()
. It is responsible for creating the object and returns it.
- __init__() -> This is for initializing the newly created object, which is passed as a parameter (the
self
parameter)
The following snippet shows how a metaclass can be created:
class MyMetaclass(type):
def __new__(cls, name, bases, dict):
print('Creating a new object of', name)
# Invoke __new__() method of the metaclass type
return super(MyMetaclass, cls).__new__(cls, name, bases, dict)
def __init__(cls, name, bases, dict):
print('Initialising class', name)
super(MyMetaclass, cls).__init__(name, bases, dict)
Now that we have created our custom Metaclass, we need to make sure we create other classes that use our metaclass.
To do this, we pass the metaclass
parameter in the new class definition, which tells the class to use our custom metaclass as it’s own metaclass, instead of type
.
class Student(metaclass=MyMetaclass):
def __init__(self, name):
self.name = name
def get_name(self):
return self.name
Here, Student
uses MyMetaclass
as its metaclass. Therefore, when creating an instance of Student, our custom metaclass methods will be called, instead of the type
metaclass.
stud = Student('Amit')
print(stud.get_name())
print('Type of Student object:', type(stud))
print('Type of Student Class:', type(Student))
Output
Creating a new object of Student
Initialising class Student
Amit
Type of Student object: <class '__main__.Student'>
Type of Student Class: <class '__main__.MyMetaclass'>
NOTE: Old Python versions of 2.7 or below use the __metaclass__
keyword for specifying the metaclass used. Python3 changed this behavior to pass the metaclass
as a parameter.
Conclusions
While metaclasses serve as a very powerful way for creating custom APIs and define their behavior during object and Class creation, they are very rarely ever used in practice, as there are other workaround methods for the same.
This article only serves as a starting point for the topic, and about understanding how Python defines everything in terms of the type
metaclass.
We looked at how metaclasses can be created, and the methods which are called during the creation of Classes.
References
StackOverflow post on Metaclasses (This provides an in-depth discussion on this topic. Recommended if you want to learn more about metaclasses): https://stackoverflow.com/questions/100003/what-are-metaclasses-in-python