Protocol System¶
Deep dive into the protocol system.
What Are Protocols?¶
Protocols are Python's way of defining structural types (also called "duck typing"). Unlike interfaces in other languages, protocols don't require explicit inheritance.
How It Works¶
from typing import Protocol
# Define the contract
class ProblemProtocol(Protocol):
@property
def name(self) -> str:
"""Problem name."""
...
@property
def code(self) -> str:
"""Diagnostic code."""
...
# Any class with these properties satisfies the protocol
class MyProblem:
def __init__(self, name: str, code: str):
self._name = name
self._code = code
@property
def name(self) -> str:
return self._name
@property
def code(self) -> str:
return self._code
# Type checker understands this works
def process_problem(problem: ProblemProtocol):
print(problem.name, problem.code)
# This is valid!
process_problem(MyProblem("Diabetes", "73211009"))
Benefits¶
- No Inheritance: Your classes stay independent
- Type Safety: IDEs and type checkers understand the contracts
- Flexibility: Works with any Python class structure
- Testability: Easy to mock and stub
Protocol Design Principles¶
Required vs Optional¶
class PatientProtocol(Protocol):
# Required properties
@property
def first_name(self) -> str: ...
@property
def last_name(self) -> str: ...
# Optional property (returns Optional type)
@property
def middle_name(self) -> Optional[str]: ...
Runtime Checking¶
Protocols are primarily for static type checking, but you can check at runtime:
from typing import runtime_checkable
@runtime_checkable
class PatientProtocol(Protocol):
@property
def first_name(self) -> str: ...
# Runtime check
if isinstance(obj, PatientProtocol):
print("It's a patient!")