Protocol Types - Structural Subtyping

Python AdvancedType SystemFree Lesson

Advertisement

Introduction

Protocol classes from typing define interfaces for structural subtyping. Unlike nominal subtyping, protocols check interface compatibility at runtime.

Basic Protocol

from typing import Protocol

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

class Circle:
    def draw(self) -> None:
        print("Drawing circle")

class Square:
    def draw(self) -> None:
        print("Drawing square")

def render(item: Drawable):
    item.draw()

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

Protocol with Type Checking

from typing import Protocol, runtime_checkable

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

class Integer:
    def __init__(self, value: int):
        self.value = value
    
    def __lt__(self, other: "Integer") -> bool:
        return self.value < other.value

a = Integer(1)
b = Integer(2)
print(a < b)  # True
isinstance(a, Comparable)  # True

Protocol Inheritance

from typing import Protocol

class Printable(Protocol):
    def print(self) -> None:
        ...

class Serializable(Protocol):
    def to_json(self) -> str:
        ...

class Document(Printable, Serializable):
    def print(self) -> None:
        pass
    
    def to_json(self) -> str:
        return "{}"

Generic Protocols

from typing import TypeVar, Generic, Protocol

T = TypeVar("T")

class Container(Protocol[T]):
    def get(self) -> T:
        ...

class Box(Generic[T]):
    def __init__(self, item: T):
        self._item = item
    
    def get(self) -> T:
        return self._item

box: Box[int] = Box(42)
container: Container[int] = box

Protocol for Duck Typing

from typing import Iterator, Iterable

def sum_all(numbers: Iterable[int]) -> int:
    return sum(numbers)

class NumberGenerator:
    def __iter__(self):
        return iter([1, 2, 3])

result = sum_all(NumberGenerator())  # Works with any iterable

Practice Problems

  1. Create a protocol for file-like objects
  2. Implement generic protocol with bounds
  3. Use runtime_checkable protocol
  4. Define protocol for database operations
  5. Create protocol composition

Advertisement

Need Expert Python Help?

Get personalized tutoring, project support, or professional consulting.

Advertisement