Что такое принцип разделения интерфейса (Interface Segregation Principle)
Что проверяют
Умеете ли вы применить принцип в языке без обязательных интерфейсов. Python не требует объявлять контракт, он проверяется утиной типизацией, и от этого ISP не исчезает: если функция принимает объект и зовёт у него десять методов, она зависит от всех десяти, объявлено это где-то или нет.
Как отвечать
Формулировка: клиент не должен зависеть от методов, которыми не пользуется. Резать надо по потребителям. Инструмент для этого Protocol из typing, потому что он описывает ровно то, что нужно вызывающей стороне, и не заставляет реализацию ни от чего наследоваться.
from typing import Protocol
class SupportsRead(Protocol):
def read(self, size: int = -1) -> bytes: ...
def parse(source: SupportsRead) -> Config:
return _parse_bytes(source.read())Функции достаточно одного метода, и теперь ей одинаково подходят файл, сокет и объект в памяти. Вариант через абстрактный базовый класс тоже рабочий, но требует явного наследования, то есть это решение поставщика, а не потребителя.
Признак нарушения в живом коде: абстрактный базовый класс, где половина наследников поднимает NotImplementedError. Такой метод нужен не всем, значит он из другого контракта.
Где спотыкаются
Отвечают, что в Python принцип неприменим, раз нет ключевого слова для интерфейса. Зависимость от лишних методов существует и без него, просто ломается она в рантайме, а не при проверке типов.
Описывают в протоколе весь класс целиком. Протокол на пятнадцать методов повторяет реализацию и не даёт ни подмены в тестах, ни свободы менять внутренности.
Путают клиента из формулировки принципа с пользователем продукта. Клиент здесь это вызывающий код, а не человек за экраном, и разделение меню в интерфейсе приложения к принципу отношения не имеет.