Документация по Python

Абстрактные базовые классы (ABCMeta)

Абстрактные базовые классы (ABCMeta)
В: Документация по Python

Установка метакласса 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):
    # атрибут метакласса всегда должен 
    # быть установлен как переменная класса 
    __metaclass__ = ABCMeta

   # декоратор abstractmethod регистрирует этот метод как undefined
   @abstractmethod 
   def virtual_method_subclasses_must_define(self):
       # Можно оставить полностью пустым
       # или предоставить базовую реализацию
       # Обратите внимание, что обычно пустая интерпретация
       # неявно возвращает `None`, но при регистрации
       # это поведение больше не применяется.

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

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() 

# AttributeError: 'ArgumentClinic' object has no attribute 'punchline'

Однако это все еще позволяет нам создавать экземпляр объекта класса 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!"

c = ArgumentClinic()
c  

# <__main__.ArgumentClinic object at 0x7fee680d3640>

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

Еще от кодкамп
Замечательно! Вы успешно подписались.
Добро пожаловать обратно! Вы успешно вошли
Вы успешно подписались на кодкамп.
Срок действия вашей ссылки истек.
Ура! Проверьте свою электронную почту на наличие волшебной ссылки для входа.
Успех! Ваша платежная информация обновлена.
Ваша платежная информация не была обновлена.