Dan Bader

Abstract Base Classes in Python

Abstract Base Classes (ABCs) enforce that derived classes implement particular methods from the base class. In this chapter you’ll learn about the benefits of abstract base classes and how to define them with Python’s built-in “abc” module.

What the ABC?

What are Abstract Base Classes good for? A while ago I had a discussion about which pattern to use for implementing a maintainable class hierarchy in Python. More specifically, the goal was to define a simple class hierarchy for a service backend in the most programmer-friendly and maintainable way.

There was a BaseService that defines a common interface and several concrete implementations that do different things but all provide the same interface (MockService, RealService, and so on). To make this relationship explicit the concrete implementations all subclass BaseService.

To be as maintainable and programmer-friendly as possible the idea was to make sure that:

  • instantiating the base class is impossible; and
  • forgetting to implement interface methods in one of the subclasses raises an error as early as possible.

When to Use Python’s abc Module

This raises the question why you’d want to use Python’s abc module. The above design problem is pretty common in more complex systems. To enforce that a derived class implements a number of methods from the base class we can use something like this Python idiom:

class Base:
    def foo(self):
        raise NotImplementedError()

    def bar(self):
        raise NotImplementedError()

class Concrete(Base):
    def foo(self):
        return 'foo() called'

    # Oh no, we forgot to override bar()...
    # def bar(self):
    #     return "bar() called"

So, what do we get from this first implementation? Calling methods on an instance of Base correctly raises NotImplementedError exceptions:

>>> b = Base()
>>> b.foo()

Furthermore, instantiating and using Concrete works as expected—and, if we call an unimplemented method on it like bar() this also raises an exception:

>>> c = Concrete()
>>> c.foo()
'foo() called'
>>> c.bar()

This first implementation is decent but it isn’t perfect yet. The downsides here are that we can still:

  • instantiate Base just fine without getting an error; and
  • provide incomplete subclasses—instantiating Concrete will not raise an error until we call the missing method bar().

With Python’s abc module was added in Python 2.6, we can do quite a bit better and solve these outstanding issues. Here’s an updated implementation using an Abstract Base Class defined with the abc module:

from abc import ABCMeta, abstractmethod

class Base(metaclass=ABCMeta):
    def foo(self):

    def bar(self):
class Concrete(Base):
    def foo(self):

    # We forget to declare bar() again...

This still behaves as expected and creates the correct class hierarchy:

assert issubclass(Concrete, Base)

Yet, we do get something awesome here. Subclasses of Base raise a TypeError at instantiation time whenever we forget to implement any abstract methods. The raised exception tells us which method or methods we’re missing:

>>> c = Concrete()
"Can't instantiate abstract class Concrete with abstract methods bar"

Without abc we’d only get a NotImplementedError if a missing method is actually called. Being notified about missing methods at instantiation time is a great advantage. It makes it more difficult to write invalid subclasses. This might not be a big deal writing new code, but a few weeks or months down the line I promise it’ll be helpful.

This pattern is not a full replacement for static-typing, of course. But in some situation it can make the resulting code more robust and more readily maintainable. Also, using abc states the code’s intent more clearly. I’d encourage you to read the abc module documentation and to start applying this pattern where it makes sense.

Object-Oriented Programming in Python: The 7 Best Learning Resources

Free download—just enter your email address below:

This article was filed under: oop, programming, and python.

Related Articles:
Latest Articles:
  • Context Managers and the “with” Statement in Python – The “with” statement in Python is regarded as an obscure feature by some. But when you peek behind the scenes of the underlying Context Manager protocol you’ll see there’s little “magic” involved.
  • Installing Python and Pip on Windows – In this tutorial you’ll learn how to set up Python and the Pip package manager on Windows 10, completely from scratch.
  • Sublime Text Settings for Writing Clean Python – How to write beautiful and clean Python by tweaking your Sublime Text settings so that they make it easier to adhere to the PEP 8 style guide recommendations.
  • How Sublime Text’s Preferences Work – Sublime Text uses a powerful text-based settings system that can be a little intimidating when you encounter it for the first time. This article gives an overview of the system and points out some common mistakes to avoid.
  • Writing Clean Python With Namedtuples – Python comes with a specialized “namedtuple” container type that doesn’t seem to get the attention it deserves. It’s one of these amazing features in Python that’s hidden in plain sight.
  • Lambda Functions in Python: What Are They Good For? – An introduction to “lambda” expressions in Python: What they’re good for, when you should use them, and when it’s best to avoid them.
← Browse All Articles