What are metaclasses in Python?
A class determines how object will behave. In Python, every type is defined by a class. The primitive data types used in other languages like int, char etc are object of int class, str class respectively. And we can make a new type by creating a class of that type.
In Python, class is itself instance of a metaclass. Metaclasses are an esoteric concept (used and understood by very less Python programmers) that defines a class’s behavior.
In Python, classes are object as well. type
is a metaclass, of
which classes are instances and type
is also instance of type
class.
An example to illustrate concept of metaclass is given as follows:
#construct a class named Fruit that does nothing
class Fruit:
pass
#object of class Fruit
apple = Fruit()
# apple is object of class fruit which is
# demonstrated by type() function
type(apple)
>>> <class '__main__.Fruit'>
#class Fruit is also an instance of metaclass type
type(Fruit)
>>> <class 'type'>
#the metaclass is also an instance of its own class type
type(type)
>>> <class 'type'>
In the above case:
- apple is an instance of
class Fruit
Fruit
is an instance class of thetype metaclass
type
is also an instance of thetype metaclass
, so it is an instance of itself
Just like a class Fruit
being instance of metaclass type
, every other
objects are also instance of metaclass type
. Like integer is also an
instance of class type
. And type
is always a instance of type class
itself.
Real Life Scenario
The metaclass is used in nested serializer in Django Rest Framework as a real life implementation.
We shall be discussing the creation of singleton classes in Python as real life example of metaclasses.
Singleton classes are those classes designed to restrict instantiations of a class to one object. It is used in the case where exactly one object is needed. The concept can be generalized to restrict the instantiation to a certain or fixed number of objects. For example:
#making a singleton class
class Singleton(type):
#we form zero instances for the class
_instances = {}
# function to ensure no extra instances are
# made except single one
def __call__(cls, *args, **kwargs):
if cls not in cls._instances:
#allocate a same address for the object even if
# more than one are made
cls._instances[cls]=super(Singleton,cls).__call__(*args,**kwargs)
return cls._instances[cls]
#we make metaclass for Singleton class as made above
class SingletonClass(metaclass=Singleton):
pass
#make x and y as the instance of SingletonClass
x = SingletonClass()
y = SingletonClass()
# both object are treated as same by allocating a same address
# i.e. no separate instances are being created.
# So both the objects are same
print(x==y)
>>>True