
Python doesn’t provide explicit support for interfaces like Java or Go. But we can implement interfaces and can enforce them at the time of class definition. The interface is generally a good programming practice where we can enforce different entities that have the same method. There are two kinds of approaches to doing this. The first one is quite simple. Python offers some metaclasses to do the job. And the second one is where we can define a metaclass and include the logic in the metaclass explicitly.
Using ABCMeta
from abc import ABCMeta, abstractmethod
class BaseClass(metaclass=ABCMeta):
def __init__(self):
pass
@abstractmethod
def method_1(self):
raise NotImplementedError()
@abstractmethod
def method_2(self):
raise NotImplementedError()
So here we defined a class which contains 2 methods and we want some other classes which inherit from the above class must define these two methods. And the base class is a metaclass so you can’t instantiate it. If you try to do the same will get this error.

Now define a class which only enforces the method_1
class A(BaseClass):
def __init__(self, a, b):
self.a = a
self.b = b
def method_1(self):
print("calling method 1")
Now if we want to instantiate class A, we will get this error

So now if we want to create a class which inherits from BaseClass then we have to define the abstract methods method_1 and method_2 . After that, we can instantiate the class.
class A(BaseClass):
def __init__(self, a, b):
self._a = a
self._b = b
def method_1(self):
print("calling method 1")
def method_2(self):
print("calling method 2")

Defining own Metaclass
Defining your own metaclass and controlling instance creation or class creation is not recommended unless you need more control over class creation, enforcing certain coding practices.
Here we first created a metaclass named BaseMeta . For explicit metaclass declaration, your class must inherit from type Class. Here the __new__ method contains the logic for enforcing interfaces. For that, we defined a structure where all the methods signature will be defined in BaseClass . Any child class which wants to implement all the methods defined BaseClass must inherit from BaseClass . One more point here we restricted the instance creation of any class whose metaclass is BaseMeta.
def _is_dunder(name):
return name.startswith('__') and name.endswith('__') and len(name)>4
class BaseMeta(type):
def __new__(cls, clsname, bases, clsdict):
method_not_defined = []
if clsname != 'BaseClass':
if BaseClass in bases:
base_cls_dict = BaseClass.__dict__
for name, meth in base_cls_dict.items():
# checks which methods are defined for enforcing in sub classes
# and also checks callables are not dunder
if (not _is_dunder(name)) and callable(meth):
# checks if methods are defined in the current class
# if not then raise Type Error
if name not in clsdict:
method_not_defined.append(name)
if method_not_defined:
raise TypeError(f'{", ".join(method_not_defined)} are not defined')
return super().__new__(cls, clsname, bases, clsdict)
def __call__(self, *args, **kwargs):
raise TypeError("Can't instantiate directly")
class BaseClass(metaclass=BaseMeta):
def __init__(self):
pass
def method_1(self):
pass
def method_2(self):
pass
Now if we want to instantiate the BaseClass then will get this error

Now let’s see if we define a class A with no methods enforced
class A(BaseClass):
pass
If we try to run the code then we will get this error

Now look what happens if we define only one method
class A(BaseClass):
def method_1(self):
print("in method 1")

So the code will not throw any error at the runtime if we define all the methods defined in BaseClass
class A(BaseClass):
def method_1(self):
print("in method 1")
def method_2(self):
print("in method 2")
It is recommended to use ABCMeta rather than defining your own metaclass .
