Python glossary entry

Protocol

typing.Protocol
Namespace
Standard library
Module
typing
Available since
Python 3.8

Describes structural compatibility: an object qualifies by providing the required operations, not by inheriting a named base.

Definition

A Protocol names the behavior an API needs. Classes can satisfy it without importing or inheriting the protocol, preserving ordinary duck typing while giving a checker a precise contract.

Describe the operation

Pyodide / WebAssembly
from typing import Protocol

class SupportsClose(Protocol):
    def close(self) -> None: ...

class Connection:
    def __init__(self) -> None:
        self.closed = False

    def close(self) -> None:
        self.closed = True

def finish(resource: SupportsClose) -> None:
    resource.close()

connection = Connection()
finish(connection)

print("[check] compatible without protocol inheritance:", SupportsClose not in Connection.__mro__)
print("[state] connection closed:", connection.closed)

The checker sees Connection.close; runtime dispatch remains an ordinary method call.

Runtime checks are deliberately shallow

Decorating a protocol with @runtime_checkable enables isinstance, but the check looks for attribute presence rather than validating complete signatures or semantics. Use it only when that shallow runtime question is useful.

Common mistake

Avoid large protocols that mirror an entire concrete class. A protocol is most useful when it states the smallest capability needed at one boundary.

Primary sourceOfficial Python documentation ↗