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
string, or anything else.
To look at the type of any Python object, if you remember, we use the
>>> 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
strs can be defined.
type is the metaclass which the language uses to create an object. (which is why every object has a type)
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
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
class Student(metaclass=MyMetaclass): def __init__(self, name): self.name = name def get_name(self): return self.name
MyMetaclass as its metaclass. Therefore, when creating an instance of Student, our custom metaclass methods will be called, instead of the
stud = Student('Amit') print(stud.get_name()) print('Type of Student object:', type(stud)) print('Type of Student Class:', type(Student))
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.
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
We looked at how metaclasses can be created, and the methods which are called during the creation of Classes.
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