Skip to main content

Include/object.h

cpython 3.14 @ ab2d84fe1023/Include/object.h

The root public header. Every C extension and every file that touches a PyObject * includes this transitively through Python.h. It declares the two fundamental structs (PyObject, PyVarObject), all refcount macros, the standard accessor macros, and the forward declaration of PyTypeObject whose full layout lives in Include/cpython/object.h.

In the free-threaded build (Py_GIL_DISABLED) the struct layout and the refcount macros both change: ob_refcnt is replaced by ob_tid plus a biased reference count word, and Py_INCREF / Py_DECREF become atomic CAS loops. The macros abstract all of that so callers compile cleanly under both build modes.

Map

LinesSymbolRolegopy
103-145PyObject / PyVarObjectCore struct layout: ob_refcnt, ob_type, ob_size.objects/object.go
147-160PyObject_HEAD / PyObject_VAR_HEADStruct-embedding macros for type definitions.objects/object.go
162-220Py_TYPE / Py_SET_TYPE / Py_REFCNT / Py_SET_REFCNT / Py_SIZE / Py_SET_SIZEType-safe accessor macros (strict since 3.10).objects/object.go
222-310PyTypeObject forward decl + slot typedefsunaryfunc, binaryfunc, ternaryfunc, etc.objects/type.go
312-420Py_INCREF / Py_DECREF / Py_XINCREF / Py_XDECREF / Py_CLEARRefcount mutation; atomic paths in free-threaded build.objects/object.go
422-530Py_RETURN_NONE / Py_RETURN_TRUE / Py_RETURN_FALSE / Py_RETURN_RICHCOMPAREConvenience return macros for C slot functions.objects/object.go
532-630_Py_CAST / _Py_REFTOTAL / _Py_NoneStruct / _Py_NotImplementedStructInternal helpers and singleton declarations.objects/object.go
632-828PyObject_* protocol functionsPyObject_IsTrue, PyObject_Repr, PyObject_Hash, PyObject_RichCompare, etc.objects/protocol.go

Reading

PyObject layout (lines 103 to 160)

cpython 3.14 @ ab2d84fe1023/Include/object.h#L103-160

/* Standard GIL build */
struct _object {
Py_ssize_t ob_refcnt;
PyTypeObject *ob_type;
};

/* Variable-length variant */
struct _var_object {
PyObject ob_base;
Py_ssize_t ob_size;
};

PyObject is the minimal prefix shared by every Python value. PyVarObject adds ob_size, which counts elements in bytes objects, lists, tuples, and all other variable-length types (it is not the allocation size).

In the free-threaded (Py_GIL_DISABLED) build the first field becomes uint64_t ob_tid (the creating thread ID used for biased reference counting), and ob_refcnt is demoted to a 16-bit field after that. The _Py_CAST helper and the Py_REFCNT macro hide the difference.

The PyObject_HEAD macro is the idiomatic way to embed the prefix in a concrete type definition. PyObject_VAR_HEAD embeds PyVarObject for variable-length types:

typedef struct {
PyObject_VAR_HEAD
PyObject **ob_item; /* pointer to first element */
Py_ssize_t allocated;
} PyListObject;

Refcount macros (lines 312 to 420)

cpython 3.14 @ ab2d84fe1023/Include/object.h#L312-420

static inline void Py_INCREF(PyObject *op) {
#if defined(Py_GIL_DISABLED)
_Py_INCREF_SPECIALIZED(op);
#else
op->ob_refcnt++;
#endif
}

static inline void Py_DECREF(PyObject *op) {
if (--op->ob_refcnt == 0) {
_Py_Dealloc(op);
}
}

Py_XINCREF / Py_XDECREF are null-safe wrappers. Py_CLEAR(p) sets p to NULL before decrementing, which prevents use-after-free when the decrement triggers a finalizer that reads p.

In gopy, reference counting is replaced by Go's garbage collector. Py_INCREF and Py_DECREF are no-ops; the macros exist in the Go source only as inline comments or are omitted entirely where Go's GC makes them redundant.

Accessor macros (lines 162 to 220)

cpython 3.14 @ ab2d84fe1023/Include/object.h#L162-220

static inline PyTypeObject* Py_TYPE(PyObject *ob) {
return ob->ob_type;
}
static inline void Py_SET_TYPE(PyObject *ob, PyTypeObject *type) {
ob->ob_type = type;
}
static inline Py_ssize_t Py_REFCNT(PyObject *ob) {
return ob->ob_refcnt;
}

Before 3.10 these were plain macros and direct field access was common. Since 3.10 the Py_LIMITED_API guard and strict-aliasing requirements force all access through the inline functions. Py_SIZE reads ob_size from a PyVarObject * and requires a cast; Py_SET_SIZE writes it. Any code that mixed ob_type field access with PY_TYPE() will generate a deprecation warning.

In gopy the analogues are methods on the Object interface: Type() *Type, SetType(*Type), Len() int.