Interface in Python

In this tutorial, we will learn how to implement the interface in Python. Generally, the interface is not part of Python, but we can implement it using the ABC module. We will understand how to interface works and cautions of Python interface creation.

Interfaces play a crucial role in software engineering as they provide a way to define a set of methods or behaviors that a class must implement. As an application grows in size and complexity, it becomes more difficult to manage updates and changes to the code base.

One common problem that arises is the presence of classes that have similar functionality but are unrelated in terms of their inheritance hierarchy. It can lead to confusion and redundancy in the codebase.

Python has a unique approach to interfaces compared to most other programming languages, and the design complexity of interfaces in Python can vary. After completing this tutorial, you will gain a better understanding of Python's data model and the differences between interfaces in Python versus those in languages such as Java, C++, and Go.

Introduction to Interface

An interface is a design template for creating classes that share common methods. The methods defined in an interface are abstract, meaning they are only outlined and lack implementation. It is unlike classes, which provide a concrete implementation for their methods. Instead, classes that implement an interface will fill in the abstract methods, giving them specific meaning and functionality.

By defining interfaces, developers can create a standard contract that classes can adhere to, regardless of their inheritance hierarchy. It allows for better code organization and reduces the likelihood of code duplication. Additionally, interfaces can provide a way to decouple components of an application, making it easier to make changes or updates to one component without affecting others.

Overall, interfaces are a powerful tool for managing complexity in software engineering, and their use can lead to more maintainable and scalable codebases.

Python follows a different approach to implementing the interface than other languages like C++, Java, and Go. These languages have interface keywords, while Python doesn't have such keywords. Python further deviates from other languages in one other aspect. It doesn't require the class to implement the interface to define all its abstract methods.

Informal Interfaces

As we know, Python is a dynamic language that allows us to implement a conversational interface. An Informal interface is a class that defines methods that can be overridden, but there is no strict enforcement.

In the following example, an informal interface will be created to extract text from various unstructured file formats, including PDFs and emails. This interface will define the necessary methods to implement in the PdfParser and EmlParser concrete classes.

Example -

The TextExtractor class defines the .load_data_source() and .extract_text() method, where the first method, load_data_source, takes in two arguments: path and file_name, both of which are of type str. This method is responsible for loading a file located at the given path with the specified file_name. The method signature indicates that the method should return a str value.

The second method, extract_text, takes in one argument: full_file_name, which is also of type str. This method is responsible for extracting text from the file specified by full_file_name, which has already been loaded into the class instance. The method signature indicates that the method should return a dict value.

As you notice, we only define these methods but not implemented. These methods will be implemented when we create the concrete classes that inherit from InformalParserInterface.

Now, we will define the two classes that implement the InformalParserInterface. To use this, we must implement the concrete class. A concrete class must inherit the interface that we that provide an implementation of the interface's method.

Example -

With the implementation of the concrete class for InformalParserInterface, extracting text from email files is now possible. However, the EmlParser defines the .extract_email_text() instead of .extract_email(). Now, we check if PdfParser and EmlParser implement TextExtractor. Let's see the following example.

As we can see the second class returns true, which violets the definition of an interface.

Using Metaclass

The desired outcome is to have issubclass(EmlParser, TextExtract) return False when the implementing class does not define all of the interface's abstract methods. In order to achieve this, a metaclass named ParserMeta will be created, and two special methods (dunder methods) will be overridden:

  1. .__instancecheck__()
  2. .__subclasscheck__()

In the code block below, you create a class called UpdatedInformalParserInterface that builds from the ParserMeta metaclass:

Example -

Now, we can create concrete implementation.

Now we implement the email parser called EmlParserNew.

In this code snippet, a metaclass named ParserMeta is used to create the UpdatedInformalParserInterface interface. The advantage of using a metaclass is that subclasses are not explicitly defined. Instead, the subclass is required to define the necessary methods. If the subclass does not define these methods, then issubclass(EmlParserNew, UpdatedInformalParserInterface) will return False.

Using Abstract Method Declaration

An abstract method is defined with the class but not implemented. These methods must be overridden by the class that inherits the class that has abstract methods.

To define the abstract method, we need to use the @abc.abstractmethod decorator to the interface's method. Let's understand the following example.

Example -

In this example, we define an interface MyInterface with a single abstract method my_method(). We use the @abc.abstractmethod decorator to mark my_method as an abstract method. Any class that inherits from MyInterface must provide an implementation for my_method.

We then define a class MyClass that implements MyInterface by providing an implementation for my_method. When we create an instance of MyClass and call my_method(), it will execute the implementation provided by MyClass.

Suppose we create a subclass of MyInterface without providing an implementation for my_method. In that case, we will get a TypeError at runtime, indicating that the subclass is not considered a complete implementation of the interface:

Conclusion

This tutorial included a detailed explanation of the interface in Python and when we needed them. Though Python doesn't have interface keywords, we can define it using multiple ways. Python provides great flexibility when creating interfaces. For small projects, an informal Python interface can be useful where you may not need to worry about return types of methods. However, a formal Python interface becomes more important as the project grows to ensure that the concrete class that implements the interface overwrites the abstract methods.

In Python, you can create a standard interface using the ABC module, which provides a way to define abstract classes and methods. You can use the @abc.abstractmethod decorator to mark a method as abstract, and any concrete class that inherits from the abstract class must provide an implementation for the abstract method.