Abstract Class and Interface¶

by Kardi Teknomo

An abstract class is a class that has methods with no implementation. Abstract class is a blueprint contract for other classes inherit from it. The abstract class cannot be instantiated, and its descendants also cannot be instantiated unless they provide implementation for methods marked by the abstractmethod decorator. The Abstract Methods in an abstract class is like a contract agreement that it must be build with certain arguments within any child classes inherited from the abstract class.

Abstract method by itself is just declaration of the name of the methods without implementation. This technique is very useful to provide common Interface for various implementation of the methods. Using Abstract class, you create the design and specification on the code that must be implemented later.

In this tutorial, you will learn about:

  • Defining Abstract Class
  • Understanding Abstract Class
  • Interface

Defining Abstract Class¶

Several ways to define an abstract class:

  1. using __metaclass__ = ABCMeta
  2. set metaclass=ABCMeta
  3. by inherit from ABC

The abstract methods in the abstract class does not need to be implemented. If it implemented, it would become a template for the children of the abstract class.

To implement the abstract class into a concrete class, it is done by inherit from the abstract class. The abstract methods must be implemented in the concrete classes.

In [1]:
from abc import ABCMeta, abstractmethod

class AbstractClass(object):
    # the metaclass attribute is used to register an abstract class 
    __metaclass__ = ABCMeta

    # this method must be build in any of the children of the Abstract class
    @abstractmethod 
    def method(self):
        pass
       
In [2]:
# Another way to register abstract class is simply by setting metaclass=ABCMeta
class AbstractClass(metaclass=ABCMeta):
    @abstractmethod 
    def method(self):
        pass
In [3]:
from abc import ABC, abstractmethod

# Another way to register abstract class is simply by inherit from ABC
class AbstractClass(ABC):
    # this method must be build in any of the children of the Abstract class
    @abstractmethod
    def method(self):
        pass

Understanding Abstract Class¶

In the code below, class Shape is not an abstract class. Rectangle class just inherit from Shape class but even if we did not implement area() method in Rectangle, there is no complain.

In [4]:
class Shape():
    def area(self):
        pass
    
class Rectangle(Shape):
    def __init__(self, width, height):
        self.width = width
        self.height = height

rectangleD = Rectangle(width=3, height=5)

To create abstract class in Python, you need to import the abstractmethod decorator and module ABC from built-in Python module Abstract Base classes (ABC).

ABC works by decorating methods of the base class as abstract and then registering concrete classes as implementations of the abstract base.

In [5]:
from abc import ABC, abstractmethod

# Shape is now an Abstract class
class Shape(ABC):
    # area method must be build in any of the children of Shape class
    @abstractmethod
    def area(self):
        pass

# Rectangle is now a concrete class of Shape 
class Rectangle(Shape):
    def __init__(self, width, height):
        self.width = width
        self.height = height
    
    # overriding abstract method
    def area(self):
        return self.width * self.height

rectangleD = Rectangle(width=3, height=5)
print('Area rectangle D is ', rectangleD.area()) 
Area rectangle D is  15

What happen if the child class did not build the method from the abstract class? Because we did not build according to the contract in the Abstract class, it would generate Exception error. This is error is by design. We deliberately make this error because it is useful to remind us that we must provide the method that already specified in the Abstract class.

Thus, the abstract method in the abstract class serves as a contract interface that must be implemented in a certain way. This is how we enforced the interface.

In [6]:
from abc import ABC, abstractmethod

# Shape is now an Abstract class
class Shape(ABC):
    # area() must be build later in any of the children of Shape class
    @abstractmethod
    def area(self):
        pass

# Rectangle is now concrete class of Shape
# but we did not build according to the contract
class Rectangle(Shape):
    def __init__(self, width, height):
        self.width = width
        self.height = height

# this would generate Exception
try:
    rectangleD = Rectangle(width=3, height=5)
except Exception as e:
    print(e)
Can't instantiate abstract class Rectangle with abstract method area

Interface¶

An Interface is a description of all functions that an object must have in order to be that object. For example, we expect a lightbulb object must have turnOn and turnOff methods. We expect a shape objects such as circle, square and rectangle would have draw method

In Python, we can create another class interface such as IShape and These methods are defined but not implemented. We then provide implementations for the declared methods.

Notice that we deliberately put raise NotImplementedError to make by designed error such that if the programmer forget to implement, it would generate error

In [7]:
class iShape():
    def draw(self):
        raise NotImplementedError

class circle(iShape):
    def draw(self):
        pass

class square(iShape):
    def draw(self):
        pass

class rectangle(iShape):
    def draw(self):
        pass

The Interface Segregation Principle¶

The interface segregation principle (ISP) states that no code should be forced to depend on methods it does not use. This principle would suggest us to create highly specialized interfaces and don't force the client to depend on unused interfaces. We splits interfaces that are very large into smaller and more specific ones so that clients will only have to know about the methods that are of interest to them.

For example, you have a class Auto with radiokit methods for all cars. If we inherit from an interface, then all methods implemented in it must be described in the descendant class. As a result, classes may receive unnecessary methods. To solve this problem, we separate the interfaces.

References¶

  • https://docs.python.org/3/library/abc.html
  • Python Interface
  • https://www.geeksforgeeks.org/abstract-base-class-abc-in-python/