Abc

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

abc помещает классы как абстрактные, а затем регистрирует конкретные классы как реализации абстрактных. Проверка принадлежности к зарегистрирвоанному абс.классу осуществляется через isinstance() и issubclass().

В collections.abc так-же реализовано несколько собственных абстрактных базовых классов. Смотри подробнее тут

Модуль abc предоставляет метакласс ABCMeta для определения абстрактных базовых классов и вспомогательный класс ABC для альтернативного определения abc посредством наследования.

from abc import ABC

class MyABC(ABC):
    pass

from abc import ABCMeta

class MyABC(metaclass=ABCMeta):
    pass

В данном примере видно, что ABC - это просто класс, который определен как класс имеющий metaclass=ABCMeta. Это сделано по причине того, что если метакласс не установлен надлежащим образом, то интерфейс не будет обязательным для реализации. По этой причине был представлен абстрактный базовый класс, в котором предусмотрено автоматическое определение метакласса.

Есть два способа зарегистрировать конкретный класс, реализующий интерфейс асбстрактного:

  • явно зарегистрирвоать подкласс
  • создать подкласс на основе абстрактного

Первый вариант выглядит так:

from abc import ABC

class MyABC(ABC):
    pass

MyABC.register(tuple)

assert issubclass(tuple, MyABC)
assert isinstance((), MyABC)

можно через декоратор

from abc import ABC

class MyABC(ABC):
    pass

class LocalClass:
    pass


@MyABC.register
class AnotherLocal(LocalClass):
    pass

assert issubclass(AnotherLocal, MyABC)

print(AnotherLocal.__mro__)
(<class '__main__.AnotherLocal'>, <class '__main__.LocalClass'>, <class 'object'>)

В первом спримере мы явно регистрируем MyABC как сабкласс асбтрактного tuple и наследуемся от абстрактного ABC. Во втором случае, не смотря на то, что AnotherLocal наследуется от LocalClass, он регистрируется как сабкласс абстрактного MyABC. Побочным эффектом первого способа является то, что мы можем запросить у базового класса список известных классов, полученных из него путем наследования через __subclasses__()

Подклассы, созданные непосредственно на основе абстрактного базового класса не могут создавать экземпляры, если в данных подклассах не реализован апи абстрактного класса. Это так называемая неполная реализация - все @abstractmethod предложенные абстрактным классом должны быть реализованы в дочерних или при попытке создать экземпляр будет поднята ошибка TypeError

Подкласы абстрактных классов могут вызывать абстрактные методы родителя через super(), но сам метод все равно потребуется реализовать

import abc


class MyABC(abc.ABC):

    @abc.abstractmethod
    def retrieve_values(self, input):
        return input.read()


class Override(MyABC):

    def retrieve_values(self, input):
        base_data = super(ConcreteOverride,
                          self).retrieve_values(input)
        return sorted(base_data.splitlines())

abstractmethod() сочетается со свойствами, методами класса и статическими методами (о реализации последних смотри в [python-descriptors]). Смотри подробнее

class C(ABC):
    @abstractmethod
    def my_abstract_method(self, arg1):
        ...
    @classmethod
    @abstractmethod
    def my_abstract_classmethod(cls, arg2):
        ...
    @staticmethod
    @abstractmethod
    def my_abstract_staticmethod(arg3):
        ...

    @property
    @abstractmethod
    def my_abstract_property(self):
        ...
    @my_abstract_property.setter
    @abstractmethod
    def my_abstract_property(self, val):
        ...

    @abstractmethod
    def _get_x(self):
        ...
    @abstractmethod
    def _set_x(self, val):
        ...
    x = property(_get_x, _set_x)

Кроме того, можно определить свойства как @setter и @getter

import abc


class Base(abc.ABC):

    @property
    @abc.abstractmethod
    def value(self):
        pass

    @value.setter
    @abc.abstractmethod
    def value(self, new_value):
        pass


class Implementation(Base):

    _value = 'Default value'

    @property
    def value(self):
        return self._value

    @value.setter
    def value(self, new_value):
        self._value = new_value

Смотри еще: