Почему / Как использовать ABCMeta и @abstractmethod

Абстрактные базовые классы (ABC) определяют, какие производные классы реализуют конкретные методы из базового класса.

Чтобы понять, как это работает и почему мы должны его использовать, давайте рассмотрим пример, который понравился бы Ван Россуму. Допустим, у нас есть базовый класс «MontyPython» с двумя методами (joke & punchline), который должен быть реализован всеми производными классами.

 class MontyPython:
    def joke(self):
        raise NotImplementedError()

    def punchline(self):
        raise NotImplementedError()

class ArgumentClinic(MontyPython):
    def joke(self):
        return "Hahahahahah"

 

Когда мы создаем объект и называем это два метода, мы получим ошибку (как и ожидалось) с punchline() метод.

  >>> sketch = ArgumentClinic() 
 >>> sketch.punchline() 
NotImplementedError 

 

Однако это все еще позволяет нам создавать экземпляр объекта класса ArgumentClinic без получения ошибки. На самом деле мы не получим ошибку, пока не найдем punchline ().

Этого можно избежать, используя модуль Abstract Base Class (ABC). Давайте посмотрим, как это работает на том же примере:

 from abc import ABCMeta, abstractmethod

class MontyPython(metaclass=ABCMeta):
    @abstractmethod
    def joke(self):
        pass

@abstractmethod
def punchline(self):
    pass

class ArgumentClinic(MontyPython):
    def joke(self):
        return "Hahahahahah"

 

На этот раз, когда мы пытаемся создать экземпляр объекта из неполного класса, мы немедленно получаем TypeError!

 >>> c = ArgumentClinic()
TypeError:
"Can't instantiate abstract class ArgumentClinic with abstract methods punchline"

 

В этом случае легко завершить класс, чтобы избежать любых ошибок типа:

 class ArgumentClinic(MontyPython):
    def joke(self):
        return "Hahahahahah"

    def punchline(self):
        return "Send in the constable!"

 

На этот раз, когда вы создаете экземпляр объекта, он работает!