Простыми словами: протоколы в PythonPython – это язык с динамической типизацией. Но что это значит на практике? Это означает, что тип переменной определяется в момент присвоения ей значения. Эта гибкость порождает риски появления ошибок, связанных с несовпадением типов переменных и параметров функций.
Например, рассмотрим простую функцию:
def add(a, b):
return a + b
Здесь a и b могут быть любыми типами, что увеличивает вероятность ошибок. Для устранения подобных проблем можно использовать аннотации типов:
def add(a: int, b: int) -> int:
return a + b
Теперь функция ясно указывает, что аргументы должны быть целыми числами. Для проверки кода можно использовать статический анализатор mypy, который выявляет потенциальные ошибки на этапе анализа программного кода.
Тем не менее, использование mypy и аннотаций типов не делает типизацию в Python статической.
Утиная типизацияСуществует также утиная типизация, которая утверждает, что функция будет работать с любым типом аргумента, если он имеет необходимые методы. Например:
def send_data(sender, data):
sender.send(data)
При этом может возникнуть вопрос, как дать понять mypy, что sender должен иметь метод send? В этом случае используются протоколы.
Протоколы в Python подобны абстрактным классам, но с другой семантикой. Они обеспечивают возможность описания интерфейсов без установки жестких ограничений:
from typing import Protocol, Mapping, Any
class SenderProtocol(Protocol):
def send(data: Mapping[str, Any]) -> None:
...
Реализация очень похожа на абстрактный класс (или, как его еще величают, интерфейс), но с другим суперклассом и отсутствием декораторов abstractmethod, abstractproperty и других вспомогательных вещей. Теперь мы можем использовать его как аннотацию типа:
def send_data(sender: SenderProtocol, data):
sender.send(data)
Все, задача выполнена! Теперь и разработчики, и статический анализатор знают, что из себя представляет из себя параметр sender.
#основы
@zen_of_python