Как называются объекты с набором фиксированных методов, например протоколы
Что проверяют
Знаете ли вы общий термин, интерфейс, и то, как эта идея устроена в Python, где ключевого слова interface нет. На деле вопрос о разнице между номинальной и структурной типизацией, и следом обычно просят сравнить Protocol с абстрактным базовым классом.
Как отвечать
В большинстве языков набор обязательных методов называется интерфейсом: interface в Java и C#, протокол в Swift, трейт в Rust. В Python три уровня:
- неформальный протокол и утиная типизация: объект итерируемый, если у него есть
__iter__, контекстный менеджер, если есть__enter__и__exit__. Никакого объявления нет, работает соглашение; - абстрактный базовый класс:
abc.ABCи@abstractmethod. Номинальная типизация: класс обязан явно наследоваться, а экземпляр с нереализованным абстрактным методом не создастся, будетTypeError. Готовые ABC лежат вcollections.abc:Iterable,Sized,Mapping; typing.Protocol(PEP 544, Python 3.8): структурная типизация. Класс не наследуется от протокола, ему достаточно иметь нужные методы с совместимыми сигнатурами, и mypy или pyright примут его там, где ожидается протокол.
Подытожьте выбором: Protocol удобен, когда вы не контролируете чужие классы или не хотите связывать модули наследованием. ABC нужен, когда важна проверка при создании объекта и общая реализация части методов в базовом классе.
Где спотыкаются
Думают, что Protocol проверяется при выполнении. Без @runtime_checkable вызов isinstance с ним бросает TypeError, а с декоратором проверяется только наличие атрибутов: сигнатуры и типы не сверяются.
Путают протокол со специальным методом. __len__ это метод, а протокол это договорённость, в которую он входит, в данном случае «размер», Sized.
Проверяют итерируемость через isinstance(x, Iterable). Объект, итерируемый через __getitem__, такую проверку не проходит, поэтому надёжный способ один: вызвать iter(x) и поймать TypeError.