Вопрос проверяет понимание того, как в Python задают контракт поведения и зачем ограничивать реализацию через интерфейсы.
В Python интерфейсы обычно реализуют через абстрактные базовые классы (ABC) или через соглашения по именам методов. Они задают набор методов, которые должен реализовать класс. Это помогает писать расширяемый и поддерживаемый код. Интерфейсы упрощают замену реализаций и тестирование.
В Python нет отдельного ключевого слова interface, как в Java, но сама идея интерфейсов активно используется.
Interface — контракт, который определяет, какие методы должен реализовать класс, не описывая их реализацию.
Самый явный и формальный способ.
from abc import ABC, abstractmethod
class PaymentService(ABC):
@abstractmethod
def pay(self, amount: int) -> None:
pass
Класс-наследник обязан реализовать метод:
class CardPayment(PaymentService):
def pay(self, amount: int) -> None:
print(f"Pay {amount} by card")
Если метод не реализован:
объект создать нельзя;
ошибка возникает сразу.
Python часто использует неявные интерфейсы.
Идея:
важно не то, от какого класса объект;
важно, какие методы у него есть.
class FileLogger:
def write(self, msg: str) -> None:
print(msg)
Если объект имеет write, он подходит, даже без наследования.
Основные причины:
снижение связности кода;
возможность легко менять реализацию;
упрощение unit-тестов (моки, стабы);
ясный контракт для разработчиков.
Интерфейсы в Python реализуют либо через ABC, либо через duck typing. Их используют, когда важно зафиксировать контракт и упростить поддержку и расширение кода.