Why use Abstract Base Classes in Python?

Viewed 93773

Because I am used to the old ways of duck typing in Python, I fail to understand the need for ABC (abstract base classes). The help is good on how to use them.

I tried to read the rationale in the PEP, but it went over my head. If I was looking for a mutable sequence container, I would check for __setitem__, or more likely try to use it (EAFP). I haven't come across a real life use for the numbers module, which does use ABCs, but that is the closest I have to understanding.

Can anyone explain the rationale to me, please?

6 Answers

Abstract method make sure that what ever method you are calling in the parent class has to be appear in child class. Below are noraml way of calling and using abstract. The program written in python3

Normal way of calling

class Parent:
    def methodone(self):
        raise NotImplemented()

    def methodtwo(self):
        raise NotImplementedError()

class Son(Parent):
   def methodone(self):
       return 'methodone() is called'

c = Son()
c.methodone()

'methodone() is called'

c.methodtwo()

NotImplementedError

With Abstract method

from abc import ABCMeta, abstractmethod

class Parent(metaclass=ABCMeta):
    @abstractmethod
    def methodone(self):
        raise NotImplementedError()
    @abstractmethod
    def methodtwo(self):
        raise NotImplementedError()

class Son(Parent):
    def methodone(self):
        return 'methodone() is called'

c = Son()

TypeError: Can't instantiate abstract class Son with abstract methods methodtwo.

Since methodtwo is not called in child class we got error. The proper implementation is below

from abc import ABCMeta, abstractmethod

class Parent(metaclass=ABCMeta):
    @abstractmethod
    def methodone(self):
        raise NotImplementedError()
    @abstractmethod
    def methodtwo(self):
        raise NotImplementedError()

class Son(Parent):
    def methodone(self):
        return 'methodone() is called'
    def methodtwo(self):
        return 'methodtwo() is called'

c = Son()
c.methodone()

'methodone() is called'

ABC's enable design patterns and frameworks to be created. Please see this pycon talk by Brandon Rhodes:

Python Design Patterns 1

The protocols within Python itself (not to mention iterators, decorators, and slots (which themselves implement the FlyWeight pattern)) are all possible because of ABC's (albeit implemented as virtual methods/classes in CPython).

Duck typing does make some patterns trivial in python, which Brandon mentions, but many other patterns continue to pop up and be useful in Python, e.g. Adapters.

In short, ABC's enable you to write scalable and reusable code. Per the GoF:

  1. Program to an interface, not an implementation (inheritance breaks encapsulation; programming to an interface promotes loose-coupling/inversion of control/the "HollyWood Principle: Don't call us, we'll call you")

  2. Favor object composition over class inheritance (delegate the work)

  3. Encapsulate the concept that varies (the open-closed principle makes classes open for extension, but closed for modification)

Additionally, with the emergence of static type checkers for Python (e.g. mypy), an ABC can be used as a type instead of Union[...] for every object a function accepts as an argument or returns. Imagine having to update the types, not the implementation, every time your code base supports a new object? That gets unmaintainable (doesn't scale) very fast.

Related