Ответ
Protocol
из модуля typing
позволяет реализовывать статическую утиную типизацию (structural subtyping). Он определяет интерфейс, которому класс может соответствовать, не наследуясь от него явно. Достаточно, чтобы класс имел те же методы и атрибуты, что и протокол.
Это позволяет писать более гибкий и слабосвязанный код, так как функции могут принимать любой объект, соответствующий нужной структуре, а не только экземпляры конкретного класса.
Ключевое отличие от ABC (Abstract Base Classes):
- ABC: требует явного наследования и регистрации (
isinstance
работает). - Protocol: не требует наследования, проверка происходит статически (например, с помощью
mypy
) на основе структуры класса.
Пример:
from typing import Protocol
# Определяем протокол: любой объект с методом go() -> str
class Movable(Protocol):
def go(self) -> str:
...
# Класс Car не наследуется от Movable, но соответствует протоколу
class Car:
def go(self) -> str:
return "Driving a car"
# Класс Person тоже соответствует
class Person:
def go(self) -> str:
return "Walking as a person"
# Функция принимает любой объект, подходящий под протокол Movable
def move_object(obj: Movable):
print(obj.go())
# Статический анализатор типов не выдаст ошибок
move_object(Car())
move_object(Person())
Для проверки соответствия протоколу во время выполнения можно использовать декоратор @runtime_checkable
.