Зачем нужна концепция интерфейса и какова ее основная цель
Что проверяют
Понимаете ли вы интерфейс как контракт между кодом, который что-то использует, и кодом, который это реализует. В Python ключевого слова interface нет, поэтому почти сразу спрашивают, чем его заменяют: ABC или Protocol, и в чём разница.
Как отвечать
Цель интерфейса: зависеть от того, что объект умеет, а не от его класса. Отсюда польза:
- замена реализации: сервис работает с
UserRepository, а за ним PostgreSQL, Redis или словарь в памяти для тестов; - полиморфизм: одна функция обрабатывает разные объекты через общий набор методов;
- инверсия зависимостей: бизнес-логика объявляет, что ей нужно, а инфраструктура подстраивается под это;
- тестируемость: вместо реального клиента подставляется фейк с тем же набором методов.
Как это выражают в Python:
- утиная типизация: объект подходит, если у него есть нужные методы. Гибко, но контракт живёт только в документации;
abc.ABCи@abstractmethod: номинальный подход, наследник обязан реализовать абстрактные методы. Проверка идёт при создании экземпляра: неполный наследник броситTypeError. В ABC могут быть и готовые методы, и состояние;typing.Protocol(с Python 3.8): структурная типизация. Наследоваться от протокола не нужно, достаточно совпадения методов, а проверяют это mypy или pyright статически. С@runtime_checkableработаетisinstance, но он смотрит только на наличие атрибутов;collections.abc: готовые контракты вродеIterableиMapping. Класс с__iter__проходитisinstance(obj, Iterable)без наследования.
На практике Protocol удобен там, где потребитель описывает, что ему нужно, а ABC там, где у наследников есть общая логика.
Где спотыкаются
Говорят, что в Python интерфейсов нет и тема неактуальна. Концепция есть, меняется только способ её выразить.
Считают, что runtime_checkable проверяет сигнатуры. Объект с методом area, который принимает не те аргументы, пройдёт isinstance.
Заводят интерфейс на каждый класс с единственной реализацией. Контракт стоит вводить там, где реализаций несколько или нужна подмена в тестах.