Protocols
A protocol is a contract that any type can satisfy by defining the right methods. The runtime dispatches through the protocol rather than checking concrete types, which is what makes the duck-typing model work.
Source-of-record: Objects/abstract.c, Lib/typing.py,
Lib/collections/abc.py.
Iterator protocol
| Method | Signature | Role |
|---|---|---|
__iter__ | (self) -> Iterator | Return an iterator. Containers return a new iterator each call. |
__next__ | (self) -> Any | Advance. Raise StopIteration to end. |
iter(obj) returns:
- The result of
obj.__iter__()if defined. - Otherwise an iterator that calls
obj.__getitem__(0),(1), ... untilIndexError(legacy).
iter(callable, sentinel) returns an iterator that calls
callable() until it returns sentinel.
Async-iterator protocol
| Method | Signature | Role |
|---|---|---|
__aiter__ | (self) -> AsyncIterator | Return async iterator. |
__anext__ | (self) -> Awaitable[Any] | Awaitable yielding next value or raising StopAsyncIteration. |
async for x in obj: calls __aiter__ once, then awaits __anext__
each iteration.
Awaitable protocol
| Method | Returns |
|---|---|
__await__ | An iterator. yield from this iterator suspends the awaiting frame. |
Native coroutines (async def) implement __await__ implicitly via
the coroutine state machine. Generator-based coroutines mark
themselves with @types.coroutine.
Sequence protocol
| Method | Role |
|---|---|
__getitem__(self, i) | Element access (int or slice). |
__setitem__(self, i, v) | Element assignment (mutable). |
__delitem__(self, i) | Element delete (mutable). |
__len__(self) | Length. |
__contains__(self, x) | Containment (optional; falls back to iteration). |
__iter__ | Optional; required only if iteration order differs from __getitem__. |
__reversed__ | Optional reverse iteration. |
__concat__ / __iconcat__ | Concatenation (operator forms via __add__). |
__repeat__ / __irepeat__ | Repetition (operator forms via __mul__). |
collections.abc.Sequence is the ABC, layering convenience methods
on the core protocol.
Mapping protocol
| Method | Role |
|---|---|
__getitem__(self, k) | Value lookup. |
__setitem__(self, k, v) | Assignment. |
__delitem__(self, k) | Delete. |
__len__(self) | Number of keys. |
__iter__(self) | Iterate keys. |
__contains__(self, k) | Key membership. |
keys(), values(), items() | Convenience accessors. |
get(k, default) | Defaulting lookup. |
__missing__(self, k) | dict.__getitem__ fallback. |
__or__ / __ror__ / __ior__ | PEP 584 dict union. |
Number protocol
The C-level number protocol exposes per-operator slots. Python-side analogues are the dunder methods (see Special methods). The key C-API entry points:
| C function | Python equivalent |
|---|---|
PyNumber_Add(a, b) | a + b |
PyNumber_InPlaceAdd(a, b) | a += b |
PyNumber_Index(a) | operator.index(a) |
PyNumber_Float(a) | float(a) |
PyNumber_Long(a) | int(a) |
PyNumber_TrueDivide(a, b) | a / b |
PyNumber_FloorDivide(a, b) | a // b |
PyNumber_MatrixMultiply(a, b) | a @ b |
PyNumber_Power(a, b, mod) | pow(a, b, mod) |
Buffer protocol (PEP 3118)
Provides zero-copy access to underlying memory. Implementing types:
| C slot | Python dunder | Role |
|---|---|---|
bf_getbuffer | __buffer__(self, flags) | Acquire view. |
bf_releasebuffer | __release_buffer__(self, view) | Release view. |
The view struct (Py_buffer) carries buf, obj, len, readonly,
itemsize, format, ndim, shape, strides, suboffsets,
internal.
memoryview is the Python-level wrapper over a Py_buffer.
Descriptor protocol
| Method | Role |
|---|---|
__get__(self, obj, objtype=None) | Attribute read. |
__set__(self, obj, value) | Attribute write (makes a data descriptor). |
__delete__(self, obj) | Attribute delete (makes a data descriptor). |
__set_name__(self, owner, name) | Called during class creation. |
Data descriptors take precedence over instance __dict__. Non-data
descriptors (only __get__) do not.
Context manager protocol
Synchronous
| Method | Role |
|---|---|
__enter__(self) | Setup. Return value bound by as. |
__exit__(self, exc_type, exc_value, traceback) | Teardown. Returns truthy to suppress. |
Asynchronous
| Method | Role |
|---|---|
__aenter__(self) -> Awaitable | Awaitable setup. |
__aexit__(self, exc_type, exc_value, tb) -> Awaitable | Awaitable teardown. |
Hash protocol
hash(x) invokes type(x).__hash__(x). The result is an int that
fits in Py_hash_t (signed pointer-width).
| Rule |
|---|
x == y implies hash(x) == hash(y). Violations are bugs. |
If __eq__ is overridden and __hash__ is not, __hash__ is set to None. |
hash(-1) is normalised to -2 (internal sentinel value). |
The PEP 456 SipHash is used for str, bytes, memoryview. |
Comparison protocol
__eq__, __lt__, __le__, __gt__, __ge__, __ne__. Reflected:
the runtime tries the right operand's reflected method if the left
returns NotImplemented. See
Expressions -> Comparisons.
Call protocol
| Slot | Role |
|---|---|
tp_call | obj(*args, **kwargs). |
tp_vectorcall | Fast path: (*args, nargsf, kwnames) packed. |
tp_vectorcall_offset | Offset into the object where the vectorcall function lives. |
Vectorcall (PEP 590)
A type with Py_TPFLAGS_HAVE_VECTORCALL set advertises an optimised
calling convention:
PyObject* vectorcallfunc(PyObject *callable,
PyObject *const *args,
size_t nargsf,
PyObject *kwnames);
| Field | Meaning |
|---|---|
callable | The callable itself. |
args | Pointer to the argument array. |
nargsf | `nargs |
kwnames | Tuple of keyword names for trailing args, or NULL. |
Many built-in callables (builtin_function_or_method, bound
methods, classes) implement vectorcall for low-overhead calls.
Generic protocol (PEP 585, 604, 695)
| Hook | Role |
|---|---|
__class_getitem__(cls, item) | cls[item] syntax (e.g. list[int]). |
__mro_entries__(self, bases) | Replace a generic alias in __bases__. |
__type_params__ | Tuple of TypeVar/TypeVarTuple/ParamSpec. |
__typing_subst__ | Used by Generic during substitution. |
Path-like protocol
| Method | Returns |
|---|---|
__fspath__(self) | str or bytes representing a filesystem path. |
os.fspath(x) is the public entry point; it accepts str, bytes,
or an object with __fspath__.
Pickle protocol
Pickling consults, in order:
- The
dispatchof the configuredPickler. __reduce_ex__(protocol).__reduce__().copyreg.__reduce_ex__defaults.
Hooks for state:
| Method | Role |
|---|---|
__getstate__() | Return state to pickle. |
__setstate__(state) | Restore from state. |
__getnewargs_ex__() | (args, kwargs) for __new__. |
__getnewargs__() | args for __new__. |
Copy protocol
copy.copy(x) consults __copy__. copy.deepcopy(x, memo) consults
__deepcopy__. If neither is defined, it falls back to the pickle
protocol.
Format protocol
format(x, spec) calls x.__format__(spec). The format spec
mini-language is described in Expressions -> f-string interpolation
and the format spec mini-language docs.
with and async with re-entrancy
Re-entering the same context manager on multiple with statements
is allowed if the manager supports it. The default
contextlib.contextmanager decorator does not; use
contextlib.contextmanager(... ) carefully or build a re-entrant
manager from scratch.
Gopy status
Every protocol listed is implemented. Built-in types pass the
ABC isinstance checks (isinstance({}, Mapping), etc.) via the
same __subclasshook__ plumbing CPython uses.
Reference
Objects/abstract.c. The protocol entry points.Lib/collections/abc.py. The ABC tier on top of the protocols.- Special methods.
- Data model.