patternpythonnoneModerate
Python typing Protocol for Structural Subtyping
Viewed 0 times
Python 3.8+
Protocolstructural subtypingduck typinginterfacePEP 544runtime_checkable
Problem
Using ABC (Abstract Base Classes) for interfaces requires explicit inheritance, preventing third-party classes from satisfying your interface without modification.
Solution
Use typing.Protocol for structural subtyping — any class with matching methods satisfies the protocol.
from typing import Protocol, runtime_checkable
@runtime_checkable
class Drawable(Protocol):
def draw(self, x: float, y: float) -> None: ...
def get_bounds(self) -> tuple[float, float, float, float]: ...
# Any class with these methods satisfies Drawable — no inheritance needed
class Circle:
def __init__(self, cx: float, cy: float, radius: float):
self.cx = cx
self.cy = cy
self.radius = radius
def draw(self, x: float, y: float) -> None:
print(f'Circle at ({x + self.cx}, {y + self.cy})')
def get_bounds(self) -> tuple[float, float, float, float]:
return (self.cx - self.radius, self.cy - self.radius,
self.cx + self.radius, self.cy + self.radius)
def render(shape: Drawable) -> None:
shape.draw(0, 0)
render(Circle(0, 0, 5)) # OK — Circle is structurally Drawable
# Runtime check with @runtime_checkable
assert isinstance(Circle(0, 0, 5), Drawable)Why
Protocol implements PEP 544 structural subtyping. Unlike ABC, it does not require explicit registration or inheritance — matching the interface structurally is sufficient for both type checkers and runtime checks.
Gotchas
- @runtime_checkable only checks for the existence of methods, not their signatures.
- Protocol classes should not have implementation — use ABC if you need default method implementations.
- Class variables in Protocols must use ClassVar to distinguish from instance attributes.
Revisions (0)
No revisions yet.