МУНИЦИПАЛЬНОЕ АВТОНОМНОЕ ОБРАЗОВАТЕЛЬНОЕ УЧРЕЖДЕНИЕ ДОПОЛНИТЕЛЬНОГО ОБРАЗОВАНИЯ
«ЦЕНТР ДЕТСКОГО ТЕХНИЧЕСКОГО ТВОРЧЕСТВА»
Методическая разработка
«Протоколы в Python»
к дополнительной общеобразовательной
общеразвивающей программе
технической направленности
«Программирование на Python»
Возраст детей: 10-17 лет
Автор: Костычев Вадим Александрович
г. Заречный Пензенской области
2026 г.
Данный материал предназначен для преподавателей информатики, программирования и студентов (учащихся), изучающих язык программирования Python. Он может быть использован как на лекциях, так и при проведении практических занятий или самостоятельной работе.
Цель: сформировать у учащихся понимание протоколов как механизма определения интерфейсов без наследования, основанного на структурной типизации, и научить использовать их для повышения надёжности и читаемости кода при статической проверке типов.
Задачи:
1. Объяснить историческое понимание «протокола» в Python (до версии 3.8).
2. Ввести понятие структурной типизации и её связь с утиной типизацией.
3. Показать, как создаются и используются протоколы через модуль typing.Protocol.
4. Продемонстрировать преимущества протоколов при работе со статическими анализаторами (mypy, PyCharm).
5. Научить проектировать гибкие интерфейсы без привязки к иерархии классов.
Что такое «протокол» в Python? (Исторический взгляд)
Долгое время в Python под протоколом понимали неформальное соглашение: если объект реализует определённые методы — он «соответствует протоколу».
Примеры:
- Протокол итерации: объект имеет метод __iter__() → его можно использовать в for.
- Протокол последовательности: объект имеет __len__() и __getitem__() → работает с len(), индексацией.
- Протокол контекстного менеджера: объект имеет __enter__() и __exit__() → работает с with.
Такие протоколы не требуют наследования — достаточно реализовать нужные методы.
Это и есть утиная типизация:
«Если ходит как утка и крякает как утка — значит, это утка»
Проблема неформальных протоколов
Хотя такой подход гибкий, у него есть недостаток:
Нет способа явно описать, какие методы должен иметь объект, чтобы соответствовать протоколу.
Разработчик должен:
- помнить правила,
- читать документацию,
- или ошибаться во время выполнения.
Статические анализаторы (вроде mypy) не могут проверить, соответствует ли объект протоколу, потому что нет формального описания.
Протоколы в Python 3.8+ (PEP 544)
Начиная с Python 3.8, появилась возможность формально описать протокол с помощью класса Protocol из модуля typing.
Базовый синтаксис:
from typing import Protocol
class Drawable(Protocol):
def draw(self) - None:
...
Теперь любой класс, имеющий метод draw(), автоматически считается совместимым с Drawable — без наследования!
Пример:
class Circle:
def draw(self) - None:
print("Рисую круг")
class Square:
def draw(self) - None:
print("Рисую квадрат")
def render(shape: Drawable) - None:
shape.draw()
render(Circle()) # OK
render(Square()) # OK
Классы Circle и Square не наследуются от Drawable, но статический анализатор (mypy) и IDE (PyCharm) примут их как корректные.
Структурная типизация
Протоколы реализуют принцип структурной типизации:
Тип A совместим с типом B, если A имеет ту же структуру (методы, атрибуты, сигнатуры), что и B.
Это отличается от номинальной типизации (как в Java/C#), где совместимость определяется явным наследованием или реализацией интерфейса.
Требования к совместимости
Чтобы класс соответствовал протоколу, он должен:
- Иметь все методы и атрибуты, указанные в протоколе.
- Иметь ту же сигнатуру (имена параметров, типы, возвращаемое значение).
Пример ошибки:
class Dog:
def speak(self, name: str) - None: # ← лишний параметр!
print(f"Гав, {name}!")
def make_sound(animal: Animal) - None: # Animal требует speak() без параметров
animal.speak()
# mypy выдаст ошибку:
# Argument 1 has incompatible type "Dog"; expected "Animal"
Преимущества протоколов
| Преимущество | Объяснение |
| Нет привязки к иерархии | Классы не обязаны наследоваться от общего родителя |
| Гибкость | Можно «подогнать» любой существующий класс под протокол |
| Статическая проверка | Ошибки находятся до запуска программы |
| Читаемость | Интерфейс явно описан в одном месте |
| Совместимость с утиной типизацией | Сохраняется философия Python: «поведение важнее типа» |
Когда использовать протоколы, а когда ABC?
| Ситуация | Рекомендуется |
| Нужна статическая проверка типов | Protocol |
| Хотите разделять поведение и реализацию | Protocol |
| Создаёте библиотеку для других разработчиков | Protocol |
| Нужны общие методы с реализацией по умолчанию | ABC |
| Требуется гарантированная реализация при создании экземпляра | ABC |
Часто Protocol и ABC дополняют друг друга.
Заключение
- Протокол — это формальное описание интерфейса без наследования.
- Он основан на структурной типизации: совместимость определяется по наличию методов и их сигнатурам.
- Протоколы позволяют использовать утиный подход с гарантиями статического анализа.
- Они особенно полезны при работе с типизированным кодом и большими проектами.
- Протоколы делают код гибким, безопасным и легко тестируемым.
Проверь себя
1. Чем протокол отличается от абстрактного базового класса?
2. Нужно ли наследоваться от Protocol, чтобы соответствовать ему?
3. Что такое структурная типизация?
4. Почему mypy может найти ошибку до запуска программы при использовании протоколов?
5. Какие требования предъявляются к методам класса, чтобы он соответствовал протоколу?
6. Можно ли использовать протоколы в Python 3.7? Почему?