1.7 Interfaces

Introduction

When working on large projects with a number of developers, or even when developing a module to release for others to make use of, there are times when you want to define functions which need to be implemented in child classes which inherit from parent classes you create. As we will see in the next module, this is useful in ensuring the Liskov Substitution design principle is maintained. For this, we make use of Interfaces, which are similar to Abstract Classes, but more abstracted and only contain the syntax requirements for function definitions that are to be implemented in the child classes which utilize the Interface.


Interfaces

Interfaces fulfill two goals:

  1. They ensure that programmers will create specific functions which are expected at Run Time.
  2. They ensure more reusable and well written code. This is because an interface is, in its simplest form, a type definition. Thus, wherever an object of that type is used in the code, it can be replaced with another object of the same type which implements that interface.

Interfaces are defined in the same way as an abstract class, except without any implementation code, and no attributes.


Interfaces vs Abstraction

Students learning OOP for the first time often get confused between Abstraction and Interfaces. The difference is quite simple; an Abstract class may contain attributes, and the functions may either be abstract (needing to be implemented in the child class) or may have implementation code, whereas interface classes are purely abstract, having no attributes and no implementation code in the functions.

The general rule of thumb is that a child class may inherit from a single parent, but implement multiple interfaces.


Interfaces in Python

To create an Interface class in Python, we use the following syntax:

from abc import ABCMeta, abstractmethod

class MyInterface:
    __metaclass__ = ABCMeta

    def someFunction(param1, param2):
        raise NotImplementedError()

    def someOtherFunction(param3):
        raise NotImplementedError()

Here, we are defining the interface class just as we would for an Abstract Class, except we have no attributes, and not implementation code. Instead, for each function we define, we have a single line of code raise NotImplementedError(). What this does is throw an exception if a child class implements this interface, but does not implement that function. In this way, we can ensure that the functions we specify in the interface are implemented in the child class.

In Python, we implement an Interface the same way we inherit from an Abstract parent class.

class myChildClass(AbstractParent, Interface1, Interface2):
    # My class implementation

Further Reading for this section

  1. Why use Interfaces in OOP?
  2. Interfaces: University of Utah

Exercises

  1. Edit the animals.py file from the previous section, and separate out the talk(), move() and breathe() functions from the parent abstract class and move these functions into an interface called "AnimalBehavior", and implement this interface in each of the child classes. Run the code to ensure it still functions and paste the completed code in a comment below for feedback.

Continue to next section


Comments

comments powered by Disqus