← Home ← Codex ← DEBT ← Engine
Browse by Category
+ added · updated 7d
← Back to glossary

Structural Subtyping with Protocol

Python Python 3.8+ Intermediate
debt(d5/e3/b3/t6)
d5 Detectability Operational debt — how invisible misuse is to your safety net

Closest to 'specialist tool catches' (d5), mypy/pyright detect Protocol mismatches and missing methods at type-check time, but without these tools structural mismatches are silent.

e3 Effort Remediation debt — work required to fix once spotted

Closest to 'simple parameterised fix' (e3), replacing an ABC with a Protocol or adding @runtime_checkable is a localized change in the type definition, though implementing classes don't need changes.

b3 Burden Structural debt — long-term weight of choosing wrong

Closest to 'localised tax' (b3), Protocols are typically defined in one module and used by consumers; they don't pervade the architecture but do shape API contracts for that component.

t6 Trap Cognitive debt — how counter-intuitive correct behaviour is

Closest to 'serious trap' (t7), the misconception that Protocol requires explicit registration like ABC contradicts how interfaces work in most other languages (Java/PHP/C#), and the runtime vs. type-check distinction with @runtime_checkable is a notable additional gotcha.

About DEBT scoring →

Also Known As

Protocol structural subtyping duck typing Python typing.Protocol runtime_checkable

TL;DR

Protocol classes define structural interfaces — any class with matching methods satisfies the protocol without explicit inheritance (type-safe duck typing).

Explanation

Protocol (typing.Protocol, Python 3.8+): a class satisfies a Protocol if it has all required attributes and methods, regardless of inheritance. Unlike ABC (which requires explicit subclassing), Protocol works at type-check time without modifying existing classes. @runtime_checkable enables isinstance() checks at runtime. Use for: typing third-party classes you cannot modify, documenting expected interfaces without coupling to a class hierarchy, and expressing duck types with static type safety.

Common Misconception

Protocol requires explicit registration like ABC — Protocol uses structural subtyping; any class with matching methods satisfies it at type-check time with no changes to the implementing class.

Why It Matters

Without Protocol, a function accepting any object with a read() method must use Any (loses type safety) or a custom ABC (requires modifying all implementing classes). Protocol gives type safety without coupling.

Common Mistakes

  • Using Protocol when ABC is more appropriate — use ABC when you want enforcement at class definition time
  • Not adding @runtime_checkable when isinstance() checks are needed
  • Protocol with mutable attributes — structural subtyping with mutable attributes can be surprising
  • Forgetting that satisfying the Protocol is checked at type-check time not runtime (without @runtime_checkable)

Code Examples

✗ Vulnerable
# Any type — loses all type safety:
def process(reader: Any) -> str:
    return reader.read()  # No type checking — any attribute access allowed

# ABC — requires modifying existing classes:
from abc import ABC, abstractmethod
class Readable(ABC):
    @abstractmethod
    def read(self) -> str: ...
# All implementing classes must inherit Readable — invasive coupling
✓ Fixed
from typing import Protocol, runtime_checkable

@runtime_checkable
class Readable(Protocol):
    def read(self) -> str: ...

def process(reader: Readable) -> str:
    return reader.read()  # Type-checked — must have read() -> str

# Any class with read() -> str satisfies it — no inheritance needed:
class FileReader:
    def read(self) -> str: return open(self.path).read()

class MockReader:
    def read(self) -> str: return 'mock data'

process(FileReader())  # Type-safe
process(MockReader())  # Type-safe
isinstance(MockReader(), Readable)  # True (runtime_checkable)

Added 16 Mar 2026
Edited 22 Mar 2026
Views 102
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
0 pings S 0 pings M 0 pings T 1 ping W 0 pings T 0 pings F 1 ping S 2 pings S 0 pings M 0 pings T 0 pings W 0 pings T 1 ping F 1 ping S 1 ping S 0 pings M 0 pings T 1 ping W 0 pings T 1 ping F 1 ping S 0 pings S 0 pings M 0 pings T 1 ping W 0 pings T 0 pings F 0 pings S 0 pings S 0 pings M
No pings yet today
No pings yesterday
Scrapy 10 Google 9 ChatGPT 7 Amazonbot 7 Perplexity 6 SEMrush 5 Ahrefs 4 Bing 4 PetalBot 4 Unknown AI 3 Claude 3 Meta AI 1 Twitter/X 1 Brave Search 1 Applebot 1
crawler 61 crawler_json 5
🧱 FUNDAMENTALS — new to this? Start with the ground floor.
Python general Python is a programming language known for readable syntax and versatility, used for web development, data science, automation, and more.

Python's gentle learning curve makes it an ideal first language, while its vast ecosystem keeps it relevant for machine learning, APIs, and DevOps. Skills transfer directly to professional environments because Python runs in production at companies of every size.

💡 When Python throws IndentationError, check that every block uses the same whitespace style—pick spaces (preferably 4) and stick with them everywhere.

Ask Codex about Python →
DEV INTEL Tools & Severity
🟡 Medium ⚙ Fix effort: Medium
⚡ Quick Fix
Use Protocol to define structural interfaces in Python — any class with the required methods satisfies the Protocol without explicit inheritance, enabling PHP-style interface checking with Python's duck typing
📦 Applies To
python 3.8 web cli
🔗 Prerequisites
🔍 Detection Hints
ABC abstract base class with all abstract methods when Protocol would be simpler; type: ignore on duck-typed arguments
Auto-detectable: ✓ Yes mypy pyright pylance
⚠ Related Problems
🤖 AI Agent
Confidence: Low False Positives: Medium ✗ Manual fix Fix: Medium Context: Class


✓ schema.org compliant