Interface in Python

Learn via video course
FREE
View all courses
Python Course for Beginners With Certification: Mastering the Essentials
Python Course for Beginners With Certification: Mastering the Essentials
by Rahul Janghu
1000
4.90
Start Learning
Python Course for Beginners With Certification: Mastering the Essentials
Python Course for Beginners With Certification: Mastering the Essentials
by Rahul Janghu
1000
4.90
Start Learning
Topics Covered

Interfaces aren't natively supported in Python, but abstract classes and methods offer a workaround. They are essential for software engineering and code organization. Interfaces, typically a set of method signatures in object-oriented programming, ensure consistency and manage updates in large applications. While Python uses the abc module, zope.interface offers stricter semantics. This article explores interfaces in Python, detailing their significance, implementation, and differences from abstract classes.

Then What Exactly is an Abstract Class?

A class that includes one or more abstract methods is referred to as an abstract class. An abstract method is one that is stated but does not have a concrete implementation; the implementation is handled by a derived class.

The important feature of interfaces is that they mandate the implementation of certain methods in classes, which is accommodated by the construction of abstract classes.

Although we are aware that interfaces are not natively supported by Python, despite this, we are anxious to master the fundamentals of interfaces in Python. Let's take a look at what makes interfaces so important.

Interface: Why are They So Crucial?

Assume we have a utility class with a method that we will utilize several times throughout our programme. What happens if we modify a utility class method's input parameters or the output that the method produces? We'd have to restructure all of the references to suit the new method signature. However, when there is a mismatch with the interface's contract, the class itself becomes invalid the class must continue with the interface and have a separate method if the signature has to be changed. In this manner, all the class's references are rather safe in how they use the utility function.

Before proceeding, let us take a step back and examine the major distinctions between an Interface and an Abstract class.

Interface vs Abstract Class

As previously demonstrated, there is no explicit 'interface' keyword in Python for establishing an interface. In Python, an abstract class with solely abstract methods is used to construct an interface. The dilemma now is when to use an abstract class and when to use an interface.

If you have a set of classes that share some common functionality and some that vary, you can use an abstract class to have concrete methods for the customary functionality supported by all the sub classes and abstract methods for the varying functionality, giving sub classes the opportunity to implement those abstract methods as needed.

If you wish to associate a group of classes in a class hierarchy even if the functionality is implemented totally differently, you may use an interface. This offers subclasses the ability to implement all abstract methods as needed.

It is now time to delve into the notion of designing and implementing interfaces in Python.

Creating and Implementing Interface in Python

Informal Interface

In some cases, you may not require the rigorous constraints of a formal Python interface. Because Python is dynamic, you may create an informal interface. An informal Python interface is a class that defines overridable methods with no tight enforcement. An informal interface, commonly known as Protocols or Duck Typing. So, if an object can fly and quack like a duck, we classify it as a duck. This is known as "Duck Typing." We depend on duck typing to let users know that they are using an interface and should treat it as such.

Let's walk through an illustration. We'll design an informal interface that describes the methods.

Code :

The two methods are defined by the InformalInterface; . read_data() and .load_data() . These methods have been described but have not yet been implemented. Once we develop subclasses that descend from InformalInterface, we shall implement these methods.

To make use of our interface, we must first develop a subclass. The methods of the interface are implemented by a subclass of the interface. To implement your interface, we'll develop two subclasses. The first is PdfReader, which will be used to extract text from PDF documents.

Code :

We'll parse the HTML documents using the second subclass, HTMLParser.

Code :

HTML documents may now be extracted using the InformalInterface subclass implementation.

So far, we've developed two InformalInterface subclasses. It should be noted, however, that HTMLParser lacks the ability to correctly define .read_data(). If we checked whether HTMLParser implements InformalInterface, we'd obtain the following:

Code :

Output :

This will return True, which is problematic because it contradicts the notion of an interface!

Let us now examine the method resolution order (MRO) of PdfReader and HTMLParser. This function informs us about the class's superclasses as well as the sequence in which they are looked for when performing a method. The dunder method classname.\_\_mro\_\_ may be used to inspect a class's method resolution order:

Note :

  • What Exactly is Method Resolution Order?

MRO (Method Resolution Order) is the order in which a programming language solves a method or attribute.

  • What Exactly Are Dunder Methods?

Dunder methods in Python are a collection of predefined methods that may be used to enhance your classes. They are easily identified because they begin and conclude with double underscores, such as \_\_init\_\_ or \_\_str\_\_.

Code :

Output :

Such informal interfaces are suitable for smaller projects with a limited number of engineers operating on the source code. However, as projects increase in size and teams expand, this might result in engineers spending countless hours searching for complex and challenging logic mistakes in the coding!

Formal Interface

A formal interface is one that is explicitly enforced. In certain cases, protocols or duck typing cause ambiguity. Consider the following illustration: we have two classes Boat and Fish, both of which contain a function Swim(), therefore the objects of both classes may swim, but they are not the same even if both classes implement the same interface. To clear up any uncertainty, we can utilize the formal interface. ABCs, or Abstract Base Classes, can assist in resolving this issue.

Abstract Base Class

An ABC is a simple interface or base class defined as an abstract class in nature, and the abstract class has certain abstract methods. Following that, if any classes or objects implement or drive from these base classes, these derived classes are required to implement all of those methods. It is important to note that the interface cannot be instantiated, which means that we cannot construct the interface's object. So we build an object using a base class, and the object implements an interface. And we'll use the type() function to determine whether or not the object implements a certain interface.Let's look at an example.

Code :

There is an ABCMeta metaclass in the abc module. This metaclass gives rise to ABCs. So we can use it directly as the metaclass of our ABC (like in class Boat(metaclass=abc.ABCMeta):) or we may subclass from the abc.ABC class, which already has the abc.ABCMeta metaclass.

Then, to make our methods abstract, we must use the @abc.abstractmethod decorator. Now, every class that inherits from our basic Boat class must also implement the swim function. Else the code would fail:

Note :

  • In Python, what is a decorator?

In Python, a decorator is a design pattern that enables users to extend an object's functionality without changing the object's structure.

Code :

We discovered the following error:

Output :

In the preceding code, the Gale class inherits the abstract class Boat but does not implement the swim() abstract function. Gale also becomes an abstract class, and so cannot be instantiated. Let us resolve this:

Code :

Also, keep in mind:

Code :

Output :

Because our Gale is identified as an instance of the Boat abstract base class, we can be certain that it surely implements our required interface based on its type.

Let us now construct another abstract base class called Fish as follows:

Code :

Now, if we contrast:

Code :

Output :

Even if both objects have the same function swim, we can now tell which one implements the Boat interface and which one implements the Fish interface.

We recently learned how to write our own abstract base classes. However, creating custom abstract base classes is frequently discouraged in favor of using subclasses; the built-in ones. The Python standard library has a plethora of helpful ABCs that we may simply reuse. The collections.abc module contains a number of handy built-in ABCs.

Registering a Virtual Subclass Using Abstract Base Classes

A class can also be registered as a virtual subclass of an abstract base class. In such a scenario, even though the class does not subclass our abstract base class, it will be viewed as a subclass of the abstract base class and so deemed to have implemented the interface. Following codes will be able to more effectively demonstrate this:

Code :

Output :

The decorator register function allows us to design a customized virtual class inheritance hierarchy.

It is preferable to declare interfaces using abstract base classes since it is evident that this is not an ordinary class; it is visibly an abstraction layer and is designed to be inherited. When we inherit from the interface but do not implement the methods, an error will be generated. If we try to initialize the interface, an error will be thrown. However, there is one minor drawback to employing abstract base classes: they are considerably too generic; ABCs may be used for a variety of purposes.

ABCs and Multiple Inheritance

A potential "issue" that might develop when utilizing abstract base classes as basic interfaces is multiple inheritance, which implies that a class can inherit from numerous abstract base classes. Consider the following example:

Code :

Output :

As a result, the Dog class has numerous parents. This was a very simplified example.

On a logical level, the difficulty is that multiple inheritance sometimes violates the classical definition of inheritance, which is a relationship. In a firm, for example, say we have employees and a cash register to pay them. Assume we have a Person class and a CashRegister class that is used to pay employees. Everything is OK if we do something like Employee(Person), i.e., the Employee class derives from Person, because the Employee is a person (for now at least). However, we could use something like Employee(Person, CashRegister) to integrate payment capabilities within the Employee class. After all, money is what defines a job. Employee is not a CashRegister, therefore this is problematic.

Interface Declaration : “ zope.interface”

The "zope.interface" is the final stop on the interface declaration tour. The ABC is a simple, versatile, and pythonic interface simulation method. However, if you want a more stringent option, there is a 3rd party package called zope.interface.

Before we begin, let's install the zope.interface 3rd party package. So that we don't have any problems while dealing with it. Run the following command on your terminal or command prompt to install zope.interface on your device.

Interface is constructed using class statements and is a subclass of interface.Interface, which serves as the parent interface for all other interfaces. The interface is declared as follows:

Syntax :

Example :

Code :

Output :

We inherited from zope.interface.Interface. So far, everything is going well. To define some class implements, we'll use the zope.interface.implementer decorator:

Syntax :

Example :

Code :

Let's have a look at some of the built-in methods given by the "zope.interface.Interface" class.

  • implementedBy(class) - returns a true or false value that is True if the class implements the interface and False otherwise.
  • providedBy(object) - returns a boolean value that is True if the object provides the interface and False otherwise.
  • providedBy(class) - always returns False since the class does not offer the interface but instead implements it.
  • list(zope.interface.implementedBy(class)) - produces a list of interfaces that a class has implemented.
  • list(zope.interface.providedBy(object)) - produces a list of interfaces that an object has provided.
  • list(zope.interface.providedBy(class)) - always produces an empty list since the class does not supply the interface but does implement it.

Here's how we employ these techniques:

Code :

Output :

So far, we've looked at numerous methods for defining and implementing interfaces in Python. Let's take a look at the Python Interface Segregation Principle.

Interface Segregation Principle

In object-oriented programming, the interface segregation principle is one of five SOLID principles, where S holds for single responsibility principle, O represents for Open-closed Principle, L accounts for Liskov Substitution Principle, I stands for Interface Segregation Principle, and D stands for Dependency Inversion Principle.

According to the interface segregation concept, an interface should be as little as feasible in terms of cohesiveness. To put it another way, it should only accomplish ONE thing.

This does not imply that the interface should only have one method. Multiple cohesive approaches are possible for an interface.

The Database interface, for example, can include connect() and detach() methods since they must be used together. The Database interface will be incomplete if neither approach is used. Let me illustrate this with an example.

To begin, create an Animal abstract class with two abstract methods, swim() and walk().

Code :

Second, create the Turtle class, which derives from the Animal class, and implement the swim() and walk() methods.

Code :

Finally, define the Fish class, which derives from the Animal class. We throw an error in the walk() function because a Fish cannot walk.

Code :

In this approach, the Fish class must implement the Animal class's walk() function, which the Fish class does not utilize. As a result, the interface segregation principle is violated by this design.

To correct this, divide the Animal class into smaller ones and inherit from these classes from the Turtle and Fish classes.

First, divide the Animal interface into two smaller interfaces: Movable and Floatable, with the Movable class inheriting from the Floatable class.

Code :

Second, the Turtle class derives from the Moveable class.

Code :

Last but not least, The Fish Class derives from the Floatable class.

Code :

The Fish just has to implement the swim() function in this design. It is not required to implement the walk() function, which it does not employ.

This concludes our tour of interfaces in Python. It may not appear to be a huge deal, but it is. In terms of types, a class that implements an interface is of the same type as the interface.

Kudos! :tada: You now have a strong knowledge of Python interfaces.

Conclusion

We learnt in this blog that:

  • Interfaces are not natively supported by Python, however abstract classes and abstract methods may be utilized to go around this.
  • Interfaces are extremely important in software engineering.
  • The primary distinction between an interface and an abstract class.
  • Python interface creation and implementation methods.
  • Concept of interface segregation, an interface should be as small as possible in terms of cohesion. To put it another way, it should only achieve ONE goal.

See Also: