PythonMiddleTechnical

Что такое abstract class в Python?

Абстрактный класс — это класс, который нельзя инстанцировать, пока наследник не реализует все методы, помеченные @abstractmethod. В Python реализуется через модуль abc (наследование от ABC или метакласс ABCMeta).

Что это

Абстрактный класс в Python — это класс, объявленный через модуль abc (наследник abc.ABC или с metaclass=abc.ABCMeta), содержащий один или несколько методов, помеченных декоратором @abstractmethod. Прямое создание экземпляра такого класса (или наследника, не переопределившего все абстрактные методы) бросает TypeError на этапе вызова __init__.

Зачем нужен

  • Зафиксировать контракт для семейства классов (например, Storage, Notifier, PaymentProvider) и получить ошибку при импорте/инстанцировании, а не глубоко в runtime.
  • Дать частичную реализацию: можно совместить @abstractmethod с обычными методами и атрибутами, наследники получат готовое поведение и обязаны доопределить только абстрактные части.
  • Поддержать виртуальное наследование через register() — пометить чужой класс как наследника без модификации его исходников.

Пример

from abc import ABC, abstractmethod

class Storage(ABC):
    @abstractmethod
    def save(self, key: str, value: bytes) -> None: ...

    @abstractmethod
    def load(self, key: str) -> bytes: ...

    # Общая реализация — наследники получат её бесплатно
    def save_text(self, key: str, text: str) -> None:
        self.save(key, text.encode("utf-8"))

class MemoryStorage(Storage):
    def __init__(self) -> None:
        self._data: dict[str, bytes] = {}

    def save(self, key: str, value: bytes) -> None:
        self._data[key] = value

    def load(self, key: str) -> bytes:
        return self._data[key]

Storage()           # TypeError: Can't instantiate abstract class Storage
MemoryStorage()     # OK — все abstractmethod переопределены

ABC vs Protocol

abc.ABC — runtime-механизм, требует явного наследования и проверяет реализацию при инстанцировании. typing.Protocol — structural typing, проверяется статически (mypy/pyright) и не требует наследования: достаточно, чтобы у объекта были нужные методы. Используйте ABC, когда важна общая реализация и runtime-проверка; Protocol — когда нужен только тип-контракт для duck typing.

Сопутствующие декораторы

  • @abstractmethod — обязательный метод.
  • @property + @abstractmethod — абстрактное свойство (порядок: @property сверху).
  • @classmethod/@staticmethod + @abstractmethod — абстрактные фабрики.

Подводные камни

  • Декоратор @abstractmethod сам по себе не работает — класс должен наследоваться от ABC или использовать ABCMeta, иначе экземпляр создастся без ошибки.
  • Старая идиома class Foo(metaclass=ABCMeta) ломает множественное наследование, если другой родитель тоже задаёт метакласс — удобнее наследоваться от ABC.
  • Класть в абстрактный класс слишком много реализации — получите жёсткую иерархию вместо контракта.
  • ABC.register(cls) делает isinstance-проверку истинной, но не проверяет, что у cls действительно есть нужные методы — это ответственность разработчика.

Common mistakes

  • Не знать abc.ABC.
  • Считать abstractmethod только документацией.
  • Не отличать ABC от Protocol.

What the interviewer is testing

  • Показывает ABC и abstractmethod.
  • Объясняет TypeError при инстанцировании.
  • Знает альтернативу Protocol.

Sources

Related topics