Include/cpython/object.h
Include/cpython/object.h is the internal counterpart to the stable Include/object.h.
It exposes the full layout of PyTypeObject (50-plus slots), the complete set of
Py_TPFLAGS_* bitmasks, the foundational PyObject_HEAD / PyObject_VAR_HEAD macros,
and PyHeapTypeObject for heap-allocated types that carry __dict__ and __weakref__.
Code that only targets the stable ABI should include object.h; code that introspects
or builds type objects directly needs this file.
Map
| Lines | Symbol | Role |
|---|---|---|
| 1–25 | PyObject_HEAD / PyObject_VAR_HEAD | Struct-prefix macros shared by every object layout |
| 26–50 | PyObject_INIT / PyObject_INIT_VAR | Inline initializers used by allocators |
| 51–80 | _PyObject_SIZE / _PyObject_VAR_SIZE | Compile-time size helpers |
| 81–180 | PyTypeObject | Full 50-plus slot struct definition |
| 181–230 | Py_TPFLAGS_* | Type-flag bitmask constants |
| 231–270 | PyHeapTypeObject | Heap-type wrapper with ht_name, ht_slots, ht_module |
| 271–300 | miscellaneous internal macros | Py_TYPE, Py_SIZE, Py_SET_TYPE, ref-count helpers |
Reading
PyObject_HEAD and PyObject_VAR_HEAD
Every CPython object begins with PyObject_HEAD, which expands to a single
PyObject ob_base member. Variable-length objects add an ob_size field via
PyObject_VAR_HEAD.
// CPython: Include/cpython/object.h:7 PyObject_HEAD
#define PyObject_HEAD PyObject ob_base;
// CPython: Include/cpython/object.h:18 PyObject_VAR_HEAD
#define PyObject_VAR_HEAD PyVarObject ob_base;
The struct layouts for PyObject and PyVarObject live in the stable header.
These macros just give C structs a named first member so that any pointer to a
CPython object can be safely cast to PyObject *.
PyTypeObject: the full slot struct
PyTypeObject is the largest struct in CPython. The abbreviated excerpt below
shows the major slot groups; each group corresponds to one of the sub-structs
(PyNumberMethods, PySequenceMethods, PyMappingMethods, etc.) that the
abstract protocol layer reads.
// CPython: Include/cpython/object.h:81 PyTypeObject
typedef struct _typeobject {
PyObject_VAR_HEAD
const char *tp_name;
Py_ssize_t tp_basicsize;
Py_ssize_t tp_itemsize;
destructor tp_dealloc;
Py_ssize_t tp_vectorcall_offset;
getattrfunc tp_getattr;
setattrfunc tp_setattr;
PyAsyncMethods *tp_as_async;
reprfunc tp_repr;
PyNumberMethods *tp_as_number;
PySequenceMethods *tp_as_sequence;
PyMappingMethods *tp_as_mapping;
hashfunc tp_hash;
ternaryfunc tp_call;
reprfunc tp_str;
getattrofunc tp_getattro;
setattrofunc tp_setattro;
PyBufferProcs *tp_as_buffer;
unsigned long tp_flags;
const char *tp_doc;
traverseproc tp_traverse;
inquiry tp_clear;
richcmpfunc tp_richcompare;
/* ... 30+ further slots ... */
} PyTypeObject;
Py_TPFLAGS bitmasks
The tp_flags field packs many boolean properties into a single unsigned long.
Key flags relevant to gopy:
// CPython: Include/cpython/object.h:181 Py_TPFLAGS_HEAPTYPE
#define Py_TPFLAGS_HEAPTYPE (1UL << 9)
#define Py_TPFLAGS_BASETYPE (1UL << 10)
#define Py_TPFLAGS_HAVE_VECTORCALL (1UL << 11)
#define Py_TPFLAGS_READY (1UL << 12)
#define Py_TPFLAGS_HAVE_GC (1UL << 14)
#define Py_TPFLAGS_METHOD_DESCRIPTOR (1UL << 17)
#define Py_TPFLAGS_HAVE_FINALIZE (1UL << 18)
#define Py_TPFLAGS_IMMUTABLETYPE (1UL << 19)
Py_TPFLAGS_HEAPTYPE distinguishes dynamically created types (classes defined
with type() or the class statement) from static types compiled into the
interpreter. Only heap types may have their tp_dict mutated after creation.
PyHeapTypeObject
Heap types carry extra fields beyond PyTypeObject for the name string, slot
descriptors, and the module reference introduced in 3.10.
// CPython: Include/cpython/object.h:231 PyHeapTypeObject
typedef struct _heaptypeobject {
PyTypeObject ht_type; /* must be first */
PyAsyncMethods as_async;
PyNumberMethods as_number;
PyMappingMethods as_mapping;
PySequenceMethods as_sequence;
PyBufferProcs as_buffer;
PyObject *ht_name; /* str: class name */
PyObject *ht_slots; /* tuple of slot names or NULL */
PyObject *ht_qualname;
struct _Py_Identifier *ht_id_name;
PyObject *ht_module; /* __module__ for 3.10+ */
char *ht_tpname; /* tp_name points here */
} PyHeapTypeObject;
Slots for number, sequence, mapping, and buffer methods are embedded inline so
that the pointer members of PyTypeObject can point directly into the same
heap allocation, avoiding a second indirection.
gopy notes
PyTypeObject is mirrored in objects/type.go as the Type struct.
Not every CPython slot has a Go counterpart yet. The current mapping:
tp_callmaps to theCallableGo interface onType.tp_richcompareis a fieldRichCompare func(a, b Object, op int) (Object, error).tp_as_number,tp_as_sequence,tp_as_mappingare represented as embedded Go interface fields (NumberProtocol,SequenceProtocol,MappingProtocol) inobjects/protocol.go.
Py_TPFLAGS_* constants are redeclared in objects/type.go as Go const
block values. Py_TPFLAGS_HEAPTYPE and Py_TPFLAGS_IMMUTABLETYPE are used by
objects/usertype.go when building class objects from the class statement.
PyHeapTypeObject corresponds to objects/usertype.go's UserType struct,
which embeds Type and adds HtName, HtSlots, HtQualname, and HtModule.
CPython 3.14 Changes
Py_TPFLAGS_MANAGED_DICT(bit 4) was added in 3.11 and is now relied upon by the per-object dict optimization;Include/cpython/object.hdocuments it prominently in 3.14.PyHeapTypeObject.ht_tpnamewas added in 3.12 to store the UTF-8 name buffer inline, removing the need for a separatePyMem_Malloccall during type creation. 3.14 documentation clarifies its lifetime rules.- The
tp_vectorcall_offsetfield interpretation is now formally stable in 3.14, having been an internal implementation detail in earlier releases.