Implement a PyTypeObject in C¶
Old C API¶
Truncated example of the PyUnicode_Type
(Python str
):
PyTypeObject PyUnicode_Type = {
PyVarObject_HEAD_INIT(&PyType_Type, 0)
"str", /* tp_name */
sizeof(PyUnicodeObject), /* tp_basicsize */
0, /* tp_itemsize */
/* Slots */
(destructor)unicode_dealloc, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_reserved */
unicode_repr, /* tp_repr */
&unicode_as_number, /* tp_as_number */
&unicode_as_sequence, /* tp_as_sequence */
&unicode_as_mapping, /* tp_as_mapping */
(hashfunc) unicode_hash, /* tp_hash*/
(...)
0, /* tp_init */
0, /* tp_alloc */
unicode_new, /* tp_new */
PyObject_Del, /* tp_free */
};
The type must then be initialized once by calling PyType_Ready()
:
if (PyType_Ready(&PyUnicode_Type) < 0) { /* handle the error */ }
This API has an obvious flaw: it rely on the exact implementation of
PyTypeObject
, the developer has to know all fields.
Variant using C99 syntax:
static PyTypeObject _abc_data_type = {
PyVarObject_HEAD_INIT(&PyType_Type, 0)
"_abc_data", /*tp_name*/
sizeof(_abc_data), /*tp_size*/
.tp_dealloc = (destructor)abc_data_dealloc,
.tp_flags = Py_TPFLAGS_DEFAULT,
.tp_alloc = PyType_GenericAlloc,
.tp_new = abc_data_new,
};
PyType_FromSpec()¶
Python 3.1 introduced a new function:
PyObject* PyType_FromSpec(PyType_Spec *spec)
Documentation:
Creates and returns a heap type object from the spec passed to the function.
There are two additional private functions (excluded from the Stable ABI):
PyObject* PyType_FromSpecWithBases(PyType_Spec*, PyObject*);
void* PyType_GetSlot(PyTypeObject*, int);
PyType_GetSlot()
expects a slot number which comes from
Include/typeslots.inc: see
slotoffsets
array. The file contains the warning:
Do not renumber the file; these numbers are part of the stable ABI.
Some slots have been disabled (bpo-10181):
/* Disabled, see #10181 */
#undef Py_bf_getbuffer
#undef Py_bf_releasebuffer
Examples of slots:
#define Py_nb_add 7
#define Py_tp_alloc 47
#define Py_tp_call 50
#define Py_tp_clear 51
#define Py_tp_doc 56
#define Py_tp_getattr 57
Example of type:
static PyType_Slot PyCursesPanel_Type_slots[] = {
{Py_tp_dealloc, PyCursesPanel_Dealloc},
{Py_tp_methods, PyCursesPanel_Methods},
{0, 0},
};
static PyType_Spec PyCursesPanel_Type_spec = {
"_curses_panel.panel",
sizeof(PyCursesPanelObject),
0,
Py_TPFLAGS_DEFAULT,
PyCursesPanel_Type_slots
};
Later initialized by:
PyObject *v = PyType_FromSpec(&PyCursesPanel_Type_spec);
if (v == NULL)
goto fail;
((PyTypeObject *)v)->tp_new = NULL;
_curses_panelstate(m)->PyCursesPanel_Type = v;
Missing fields:
- To provide a __dict__ in a defined C type, tp_dict_offset slot must be set, but this slot is missing from the stable ABI.
- Same issue with tp_weaklistoffset
PyStructSequence_InitType()¶
There are two public APIs for structure sequences that are wrappers around
PyType_Ready()
for initializing a PyTypeObject
in-place:
PyStructSequence_InitType()
PyStructSequence_InitType2()
A third-party developer should prefer PyStructSequence_NewType()
to create
a type object from an array of PyStructSequence_Desc
.