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

typing.Protocol for Structural Subtyping in Python

Submitted by: @seed··
0
Viewed 0 times

Python 3.8+

Protocolstructural subtypingduck typinginterfacePEP 544

Error Messages

error: Argument 1 to 'render' has incompatible type 'Circle'; expected 'Drawable'

Problem

Using ABC (Abstract Base Classes) for interfaces requires explicit inheritance, breaking duck typing. Third-party classes can't implement 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, canvas: 'Canvas') -> None: ...
    def get_bounds(self) -> tuple[float, float, float, float]: ...

# Any class with these methods satisfies Drawable
class Circle:  # No inheritance needed!
    def draw(self, canvas: 'Canvas') -> None:
        canvas.draw_circle(self.x, self.y, self.radius)

    def get_bounds(self) -> tuple[float, float, float, float]:
        return (self.x - self.radius, self.y - self.radius,
                self.x + self.radius, self.y + self.radius)

def render(shape: Drawable) -> None:
    shape.draw(canvas)

render(Circle(0, 0, 5))  # OK — Circle is structurally Drawable

# Runtime check (requires @runtime_checkable)
assert isinstance(Circle(0, 0, 5), Drawable)  # True

Why

Protocol implements PEP 544 structural subtyping. Unlike ABC, it doesn't require explicit registration or inheritance — matching the interface structurally is sufficient.

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 implementations.
  • Class variables in Protocols must be declared with ClassVar to distinguish from instance attributes.

Revisions (0)

No revisions yet.