Введение

Примеры

Установка метакласса ABCMeta

Абстрактные классы - это классы, которые предназначены для наследования, но избегают реализации конкретных методов, оставляя только сигнатуры методов, которые должны реализовывать подклассы.

Абстрактные классы полезны для определения и реализации абстракций классов на высоком уровне, аналогично концепции интерфейсов в типизированных языках, без необходимости реализации метода.

Один концептуальный подход к определению абстрактного класса состоит в том, чтобы заглушить методы класса, а затем вызвать NotImplementedError при обращении к нему. Это предотвращает доступ дочерних классов к родительским методам без их переопределения. Вот так:

 class Fruit:

    def check_ripeness(self):
        raise NotImplementedError("check_ripeness method not implemented!")


class Apple(Fruit):
    pass


a = Apple()
a.check_ripeness() # raises NotImplementedError


 

Создание абстрактного класса таким способом предотвращает ненадлежащее использование методов, которые не переопределяются, и, конечно, поощряет определение методов в дочерних классах, но не обеспечивает их определение. С abc модуля мы можем предотвратить дочерние классы от того экземпляра , когда они не могут переопределить абстрактные методы класса своих родителей и предков:

 from abc import ABCMeta

class AbstractClass(object):
    # the metaclass attribute must always be set as a class variable 
    __metaclass__ = ABCMeta

   # the abstractmethod decorator registers this method as undefined
   @abstractmethod 
   def virtual_method_subclasses_must_define(self):
       # Can be left completely blank, or a base implementation can be provided
       # Note that ordinarily a blank interpretation implicitly returns `None`, 
       # but by registering, this behaviour is no longer enforced.

 

Теперь можно просто создать подкласс и переопределить:

 class Subclass(AbstractClass):
    def virtual_method_subclasses_must_define(self):
        return 

Почему / Как использовать 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!"

 

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

Синтаксис

Параметры

Примечания