Does Python Have Interfaces?


Does Python Have Interfaces?

Python claims to be a multi-paradigm language with rich OOP capabilities. It has a lot of features that are a must-have for a modern object-oriented programming language - but is interface on of these? Are there interfaces in Python?

Python does not have interfaces, but the same functionality can be achieved with the help of abstract base classes and multiple inheritance. The reason for not having interfaces is that Python does not use static typing, so there’s no compile-time type checking.

In this article we’ll look into what duck typing is, how to use Python’s abstract base classes, and what other options you have in Python regarding interfaces.

What Is An Interface?

In Object Oriented Programming an interface is a construct that can be used to enforce a set of properties or methods on a class that implements the interface. It is similar to a parent class, with the difference that it is completely abstract - it defines the signature of the required methods, but provides no default implementation.

Why Python Does Not Support Interfaces?

In statically typed languages like Java or C#, type checking happens at compile time. Python however, is a dynamically typed language, which means that there are no compile-time guarantees for type-safety, so an interface would not be that useful.

Static Typing vs Duck Typing

In statically typed languages you have to explicitly define the type of your variables, and the compiler will throw an error if you try to assign a different type of object to a variable.

In Python you do not have to do that, the type system is based on the following motto:

If it walks like a duck and it quacks like a duck, then it must be a duck.

Which means, that Python interpreter does not need to know the type of an object - so it is not required explicitly declare it. If the object has the necessary methods (implicitly implements the interface) - it is “good enough” for Python. The downside is that typechecking happens only at runtime.

Proposal For Python Interfaces

In fact, there was an attempt to introduce the interface keyword to Python. In 2001, Michel Pelletier created PEP-245, with proposed a syntax and a behaviour for interfaces. After 5 years it got refused by Guido van Rossum, with the following note:

While at some point I expect that Python will have interfaces, it would be naive to expect it to resemble the syntax in this PEP. Also, PEP 246 is being rejected in favor of something completely different; interfaces won’t play a role in adaptation or whatever will replace it.

Defining/Using Interfaces in Python

So what does Python have instead of interfaces? If you want to use interface-like constructs, you should look into the abc package.

Abstract Base Classes

The abc package contains some handy tools for defining Abstract Base Classes. ABCs can have one or more abstract method or property. The methods/properties must be overridden by any inheriting class, otherwise it the class can not be instantiated.

Let’s see an example:

from abc import ABC, abstractmethod

class Animal(ABC):
    @abstractmethod
    def make_a_noise():
        pass

If we define child class without overriding the abstract method:

class Dog(Animal):
    pass

The Python interpreter won’t let us instantiate it:

fluffy = Dog()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Can't instantiate abstract class Dog with abstract methods make_a_noise

Let’s fix that:

class Dog(Animal):
    def make_a_noise():
        return "bark"

Note: unlike most other languages Python’s abstract methods can have an implementation (to be called via super()). So this is completely valid:

from abc import ABC, abstractmethod

class Animal(ABC):
    @abstractmethod
    def make_a_noise():
        return None 

class Fish(Animal):
    def make_a_noise():
        return super().make_a_noise() 

If you don’t want your method to have a default implementation, you can leave the function body empty (just write a single pass statement) or raise a NotImplementedError

Multiple Inheritance

In Python any class can have multiple parent classes - which means that a class can inherit from multiple abstract base classes (the equivalent of implementing multiple interfaces).

A simplistic example:

from abc import ABC, abstractmethod

class Animal(ABC):
    @abstractmethod
    def make_a_noise():
        pass

class Pet(ABC):
    @abstractmethod
    def play():
        pass

class Dog(Animal, Pet):
    def make_a_noise():
        return "bark" 

    def play():
        return "fetch a ball" 

Alternative Options For Python Interfaces

The ABC is a clean, flexible and pythonic way of simulating interfaces. However, if you are looking for an alternative that is a bit more strict, there is a 3rd party package called interface:

The interface Package

The interface package provides an alternative interface implementation for Python. The syntax is similar to that of Java, and the behaviour is also closer to it, as interface implementations are checked when the implementing class is loaded - not when the class is instantiated.

To install the package, you can use pip:

pip install python-interface

The previous example with interfaces instead of ABCs:

from interface import implements, Interface

class Animal(Interface):
    def make_a_noise(self):
        pass

class Dog(implements(Animal)):
    def make_a_noise(self, x):
        return "bark"

Summary

Python does not have interfaces, as they are not really need as a separate language construct - according to Python’s philosophy, “there should one obvious way to do it”. In Python you can use Abstract Base Classes in place of interfaces - multiple inheritence, and dynamic typing makes them even more flexible, at the price of sacrificing the safety of compile-time type-checking.

References