Skip to content

Python Interface: How to Use and Fix Interfaces Effortlessly

[

Implementing an Interface in Python

Interfaces play an important role in software engineering. As an application grows, updates and changes to the code base become more difficult to manage. More often than not, you wind up having classes that look very similar but are unrelated, which can lead to some confusion. In this tutorial, you’ll see how you can use a Python interface to help determine what class you should use to tackle the current problem.

Python Interface Overview

At a high level, an interface acts as a blueprint for designing classes. Like classes, interfaces define methods. Unlike classes, these methods are abstract. An abstract method is one that the interface simply defines. It doesn’t implement the methods. This is done by classes, which then implement the interface and give concrete meaning to the interface’s abstract methods.

Python’s approach to interface design is somewhat different when compared to languages like Java, Go, and C++. These languages all have an interface keyword, while Python does not. Python further deviates from other languages in one other aspect. It doesn’t require the class that’s implementing the interface to define all of the interface’s abstract methods.

Informal Interfaces

In certain circumstances, you may not need the strict rules of a formal Python interface. Python’s dynamic nature allows you to implement an informal interface. An informal Python interface is a class that defines methods that can be overridden, but there’s no strict enforcement.

In the following example, you’ll take the perspective of a data engineer who needs to extract text from various different unstructured file types, like PDFs and emails. You’ll create an informal interface that defines the methods that will be in both the PdfParser and EmlParser concrete classes:

class InformalParserInterface:
def load_data_source(self, path: str, file_name: str) -> str:
"""Load in the file for extracting text."""
pass
def extract_text(self, full_file_name: str) -> dict:
"""Extract text from the currently loaded file."""
pass

The InformalParserInterface defines the two methods .load_data_source() and .extract_text(). These methods are the blueprint for the PdfParser and EmlParser classes.

Now let’s implement the PdfParser class:

class PdfParser(InformalParserInterface):
def load_data_source(self, path: str, file_name: str) -> str:
# Implementation specific to loading data from a PDF file
pass
def extract_text(self, full_file_name: str) -> dict:
# Implementation specific to extracting text from a PDF file
pass

And the EmlParser class:

class EmlParser(InformalParserInterface):
def load_data_source(self, path: str, file_name: str) -> str:
# Implementation specific to loading data from an email file
pass
def extract_text(self, full_file_name: str) -> dict:
# Implementation specific to extracting text from an email file
pass

With this implementation, both the PdfParser and EmlParser classes adhere to the methods defined in the InformalParserInterface interface. They implement the methods in their own specific way, but the interface provides a common blueprint for how these classes should behave.

Formal Interfaces

While informal interfaces can be useful in certain scenarios, there may be cases where you want a stricter enforcement of interface conformance. Python provides a module called abc (Abstract Base Classes) that allows you to create a formal interface using abc.ABCMeta and @abc.abstractmethod.

Here’s an example of how you can create a formal interface using abc:

import abc
class FormalParserInterface(metaclass=abc.ABCMeta):
@abc.abstractmethod
def load_data_source(self, path: str, file_name: str) -> str:
"""Load in the file for extracting text."""
@abc.abstractmethod
def extract_text(self, full_file_name: str) -> dict:
"""Extract text from the currently loaded file."""

The FormalParserInterface class is defined as an abstract base class using the abc.ABCMeta metaclass. The @abc.abstractmethod decorator is used to define abstract methods that must be implemented by any class that inherits from this interface.

To implement the formal interface, you would need to override all the abstract methods. For example:

class PdfParser(FormalParserInterface):
def load_data_source(self, path: str, file_name: str) -> str:
# Implementation specific to loading data from a PDF file
pass
def extract_text(self, full_file_name: str) -> dict:
# Implementation specific to extracting text from a PDF file
pass

Using the formal interface ensures that any class implementing it is required to provide the specific functionality defined by the interface.

Conclusion

In this tutorial, you’ve learned about interfaces in Python and how they can help define the blueprint for classes. You’ve seen examples of both informal and formal interfaces, and how they can be implemented in Python. By using interfaces, you can better manage code complexity and ensure that classes conform to a specific set of rules and behaviors.