← Назад к вопросам

Используешь ли Protocol из библиотеки typing в Python

1.7 Middle🔥 131 комментариев
#Python Core

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Protocol в Python: Структурная типизация

Да, я активно использую Protocol из модуля typing. Это инструмент для реализации структурной типизации (duck typing with types) в Python.

Что такое Protocol?

Protocol — это интерфейс, который определяет набор методов и атрибутов, которые должен иметь объект. В отличие от классического наследования, объект не обязательно должен явно наследоваться от Protocol — достаточно иметь нужные методы.

from typing import Protocol

class Drawable(Protocol):
    def draw(self) -> None:
        ...

class Circle:
    def draw(self) -> None:
        print("Рисую круг")

class Square:
    def draw(self) -> None:
        print("Рисую квадрат")

def render(obj: Drawable) -> None:
    obj.draw()

render(Circle())
render(Square())

Protocol vs ABC vs Inheritance

Protocol (структурная типизация)

from typing import Protocol

class Comparable(Protocol):
    def __lt__(self, other: "Comparable") -> bool: ...
    def __eq__(self, other: object) -> bool: ...

class Version:
    def __init__(self, major: int, minor: int):
        self.major = major
        self.minor = minor
    
    def __lt__(self, other: "Version") -> bool:
        return (self.major, self.minor) < (other.major, other.minor)
    
    def __eq__(self, other: object) -> bool:
        if not isinstance(other, Version):
            return False
        return (self.major, self.minor) == (other.major, other.minor)

def find_min(items: list[Comparable]) -> Comparable:
    return min(items)

ABC (абстрактный базовый класс)

from abc import ABC, abstractmethod

class Animal(ABC):
    @abstractmethod
    def make_sound(self) -> None:
        pass

class Dog(Animal):
    def make_sound(self) -> None:
        print("Гав")

Реальные примеры использования Protocol

1. Context Manager Protocol

from typing import Protocol

class ContextManager(Protocol):
    def __enter__(self) -> "ContextManager":
        ...
    def __exit__(self, exc_type, exc_val, exc_tb) -> bool:
        ...

class Database(ContextManager):
    def __enter__(self):
        print("Подключение к БД")
        return self
    
    def __exit__(self, exc_type, exc_val, exc_tb):
        print("Закрытие БД")
        return False

2. Repository Pattern

from typing import Protocol, Generic, TypeVar

T = TypeVar("T")

class Repository(Protocol[T]):
    def find_by_id(self, id: int) -> T | None: ...
    def save(self, item: T) -> None: ...
    def delete(self, id: int) -> None: ...

class User:
    def __init__(self, id: int, name: str):
        self.id = id
        self.name = name

class UserRepository:
    def find_by_id(self, id: int) -> User | None:
        pass
    
    def save(self, item: User) -> None:
        pass
    
    def delete(self, id: int) -> None:
        pass

Runtime checkable

from typing import Protocol, runtime_checkable

@runtime_checkable
class Hashable(Protocol):
    def __hash__(self) -> int: ...

class MyClass:
    def __hash__(self) -> int:
        return 42

obj = MyClass()
print(isinstance(obj, Hashable))

Когда использовать Protocol?

  • Зависимости — не привязываем код к конкретным классам
  • Тестирование — легче создавать mock-объекты
  • Расширяемость — новые классы работают с интерфейсом
  • Duck typing with types — Python way с типизацией
  • Инверсия зависимостей — следуем SOLID принципам