Абстрактный класс - очень важная концепция объектно-ориентированного программирования. Это хорошая практика принципа "не повторяйся". В большом проекте дублирование кода примерно равно повторному использованию ошибок, и один разработчик не может запомнить детали всех классов. Поэтому очень полезно использовать абстрактный класс для определения общего интерфейса для различных реализаций.
Абстрактный класс имеет некоторые особенности, а именно:
Короче говоря, абстрактный класс определяет общий интерфейс для набора подклассов. Он предоставляет общие атрибуты и методы для всех подклассов, чтобы уменьшить дублирование кода. Он также заставляет подклассы реализовывать абстрактные методы, чтобы избежать каких-то несоответствий.
Python поставляется с модулем под названием abc
, который предоставляет полезные вещи для абстрактного класса. Абстрактный класс можно определить с помощью класса abc.ABC
, а абстрактный метод определить с помощью abc.abstractmethod
. ABC
- это аббревиатура, сокращение от слов абстрактный базовый класс.
Примечание: Класс не является настоящим абстрактным, если он имеет абстрактные методы, но не наследуется от abc.ABC
, это означает, что он может быть создан. Например:
from abc import ABC, abstractmethod class Animal(ABC): @abstractmethod def move(self): pass a = Animal() # TypeError: Can't instantiate abstract class Animal with abstract methods move class Animal(): @abstractmethod def move(self): pass a = Animal()
Декоратор @abstractmethod
может использоваться для объявления абстрактных методов свойств и дескрипторов требует, чтобы метакласс класса был ABCMeta или производным от него. Абстрактный класс не может быть создан, пока не будут переопределены все его абстрактные методы и свойства.
На самом деле абстрактный метод в Python не обязательно должен быть "полностью абстрактным", что отличается от некоторых других объектно-ориентированных языков программирования. Можно определить некоторые общие вещи в абстрактном методе и использовать функцию super()
для вызова его в подклассах.
from abc import ABC, abstractmethod class Animal(ABC): @abstractmethod def move(self): print('Animal moves') class Cat(Animal): def move(self): super().move() print('Cat moves') c = Cat() c.move() # Animal moves # Cat moves
Как показано в приведенном выше примере, абстрактный метод .move()
может содержать некоторые функции и может вызываться подклассом с помощью super()
. Хотя у него небольшая реализация, это все еще абстрактный метод, и пользователю необходимо полностью реализовать его в подклассах.
Совместно с декоратором @abstractmethod
можно использовать такие декораторы, как @property
, @classmethod
и @staticmethod
. Когда декоратор @abstractmethod
применяется в сочетании с другими дескрипторами методов, его следует применять как самый внутренний декоратор
from abc import ABC, abstractmethod class C(ABC): @classmethod @abstractmethod def my_abstract_classmethod(cls, ...): ...
from abc import ABC, abstractmethod class C(ABC): @staticmethod @abstractmethod def my_abstract_staticmethod(...): ...
В приведенном примере определяется свойство только для чтения:
from abc import ABC, abstractmethod class C(ABC): @property @abstractmethod def my_abstract_property(self): ...
Также можно определить абстрактное свойство для чтения и записи, соответствующим образом пометив один или несколько базовых методов как абстрактные:
from abc import ABC, abstractmethod class C(ABC): @property def x(self): ... @x.setter @abstractmethod def x(self, val): ...
Если только некоторые компоненты являются абстрактными, только эти компоненты необходимо обновить, чтобы создать конкретное свойство в подклассе:
class D(C): @C.x.setter def x(self, val): ...
Динамическое добавление абстрактных методов в класс или попытка изменить статус абстракции метода или класса после его создания поддерживаются только с помощью функции abc.update_abstractmethods()
.
abc.update_abstractmethods(cls)
:Новое в версии Python 3.10.
Функция abc.update_abstractmethods(cls)
предназначена для пересчета статуса абстракции абстрактного класса. Эту функцию следует вызывать, если абстрактные методы класса были реализованы или изменены после их создания. Обычно эту функцию следует вызывать из декоратора класса.
Возвращает cls
, чтобы разрешить использование в качестве декоратора класса.
Если cls
не является экземпляром ABC
, ничего не делает.
Примечание. Эта функция предполагает, что суперклассы cls
уже обновлены. Она не обновляет никаких подклассов.
from abc import ABC, abstractmethod class C(ABC): @abstractmethod def my_abstract_method(self, ...): ... @classmethod @abstractmethod def my_abstract_classmethod(cls, ...): ... @staticmethod @abstractmethod def my_abstract_staticmethod(...): ... @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)