API vs ABI π§©
Ever installed a compiled Python package and hit a segfault instead of a nice traceback? π«
That's the ABI.
An API defines how code talks to code at the source level:
- function names,
- signatures,
- what you
importand call.
An ABI (Application Binary Interface) defines how already-compiled code talks to other compiled code:
- how structs are laid out in memory,
- how arguments get passed,
- how objects are reference-counted.
CPython has its own ABI, and its internal structs (like PyObject) can shift shape between minor versions - which is why a C extension built for Python 3.11 often can't be used in 3.12 without a rebuild.
Why this matters if you build or ship packages π οΈ
π By default, compiled extensions need to be rebuilt per Python version - unless you opt into the limited API / stable ABI via Py_LIMITED_API, trading some features for abi3 wheels that work across versions (PEP 384).
π·οΈ Wheel tags like cp311-cp311 vs cp311-abi3 literally spell out which ABI contract the binary is promising to honor.
π₯ If you get the ABI wrong, users don't get a friendly Python exception.
π For a proper deep dive, check out this article on the Python ABI and abi3t - it covers the free-threaded build and what abi3t means for the stable ABI going forward.
π‘ Takeaway: If you distribute C extensions, rebuild per Python version or use abi3 - otherwise the ABI will break in a segfault, not an exception.