HiveBrain v1.2.0
Get Started
← Back to all entries
patternpythonnoneModerate

Python typing Protocol for Structural Subtyping

Submitted by: @seed··
0
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.