Implementing an Interface in Python – Real Python

Kai Nguyen

Hatched by Kai Nguyen

Mar 26, 2024

4 min read

0

Implementing an Interface in Python – Real Python

At a high level, an interface acts as a blueprint for designing classes. Interfaces define methods, and these methods are abstract, meaning they simply define the method without implementing it. In Python, an informal interface is a class that defines methods that can be overridden, but there's no strict enforcement. Instead, Python relies on duck typing to inform users that this is an interface and should be used accordingly. To use an interface, you must create a concrete class, which is a subclass of the interface that provides an implementation of the interface's methods.

While informal interfaces can be useful for projects with a small code base and a limited number of programmers, as projects get larger and teams grow, this approach could lead to developers spending countless hours looking for hard-to-find logic errors in the codebase. To address this issue, Python provides the concept of virtual base classes.

Virtual base classes use the .__subclasscheck__() dunder method to implicitly check if a class is a virtual subclass of the superclass. Unlike regular subclasses, virtual base classes don't appear in the subclass's method resolution order (MRO). By using virtual base classes, you can enforce strict adherence to the interface, reducing the chances of subtle bugs creeping into your codebase.

Formal interfaces, on the other hand, utilize Python's built-in ABCMeta from the abc module. To create a formal interface, you can directly register a virtual subclass by using the .register() metamethod. In this case, you'll use abc.ABCMeta as the metaclass. Then, you'll overwrite .__subclasshook__() in place of .instancecheck() and .subclasscheck(). However, it's important to be careful when combining .__subclasshook__() with .register(), as .__subclasshook__() takes precedence over virtual subclass registration.

By using a metaclass, you don't need to explicitly define the subclasses that implement the interface. Instead, the subclass must define the required methods specified by the interface. An abstract method is a method that's declared by the Python interface, but it may not have a useful implementation. This abstract method must be overridden by the concrete class that implements the interface.

Coroutines - Wikipedia

Coroutines are computer program components that allow execution to be suspended and resumed, generalizing subroutines for cooperative multitasking. They have been described as "functions whose execution you can pause." The term "coroutine" was coined by Melvin Conway in 1958 when he applied it to the construction of an assembly program. While subroutines are special cases of coroutines, there are some fundamental differences between the two.

One of the key differences is that coroutines are cooperatively multitasked, whereas threads are typically preemptively multitasked. This means that the execution of coroutines relies on cooperation between different parts of the program, while threads can be interrupted and resumed by the operating system. Additionally, values of data local to a coroutine persist between successive calls, providing a way to maintain state within the coroutine.

In 1980, Christopher D. Marlin summarized two widely-acknowledged fundamental characteristics of a coroutine. First, the execution of a coroutine is suspended as control leaves it. This allows for the coroutine to be paused and resumed at specific points in the program. Second, unlike subroutines, coroutines can be invoked multiple times and hold state between invocations. This means that a coroutine can return multiple times, allowing for more flexible control flow.

Coroutines provide concurrency, allowing different parts of a program to execute in parallel. However, it's important to note that coroutines do not provide parallelism in the same way that threads or processes do. Switching between coroutines doesn't necessarily involve any system calls or blocking calls, making them lightweight and efficient.

Generators, also known as semicoroutines, are a subset of coroutines. They allow for the easy iteration over a sequence of values, pausing and resuming execution at each iteration. Generators are commonly used in Python for tasks such as reading large files or generating large sequences of data.

Using coroutines for state machines or concurrency is similar to using mutual recursion with tail calls. By structuring your program as a set of cooperating coroutines, you can achieve complex behavior while maintaining a clear and concise codebase.

In conclusion, both implementing interfaces in Python and using coroutines provide powerful tools for organizing and structuring your code. When working with larger projects and teams, formal interfaces and virtual base classes can help enforce adherence to the interface, reducing the chances of logic errors. On the other hand, coroutines offer a way to achieve cooperative multitasking and concurrency, allowing for more efficient and flexible program execution.

Actionable Advice:

  1. When working on larger projects, consider using formal interfaces and virtual base classes to enforce adherence to the interface. This can help reduce the chances of logic errors and make your code easier to manage.
  2. Experiment with coroutines to achieve cooperative multitasking and concurrency in your programs. By structuring your code as a set of cooperating coroutines, you can achieve complex behavior while maintaining a clear and concise codebase.
  3. Take advantage of generators, a subset of coroutines, for tasks such as reading large files or generating large sequences of data. Generators provide an efficient and convenient way to iterate over sequences while pausing and resuming execution.

Sources

← Back to Library

Hatch New Ideas with Glasp AI 🐣

Glasp AI allows you to hatch new ideas based on your curated content. Let's curate and create with Glasp AI :)

Start Hatching 🐣