6. Creating New Types

The creation of new extension types (AKA ‘classes’) is pretty well described in the Python documentation tutorial and reference. This section just describes a rag bag of tricks and examples.

6.1. Properties

6.1.1. Referencing Existing Properties

If the property is part of the extension type then it is fairly easy to make it directly accessible as described here

For example the Noddy struct has a Python object (a string) and a C object (an int):

typedef struct {
    PyObject_HEAD
    PyObject *first; /* first name */
    /* ... */
    int number;
} Noddy;

These can be exposed by identifying them as members with an array of PyMemberDef like this:

static PyMemberDef Noddy_members[] = {
    {"first", T_OBJECT_EX, offsetof(Noddy, first), 0,
     "first name"},
    /* ... */
    {"number", T_INT, offsetof(Noddy, number), 0,
     "noddy number"},
    {NULL}  /* Sentinel */
};

And the type struct must reference this array of PyMemberDef thus:

static PyTypeObject NoddyType = {
    /* ... */
    Noddy_members,             /* tp_members */
    /* ... */
};

Reference to PyMemberdef.

6.1.2. Created Properties

If the properties are not directly accessible, for example they might need to be created, then an array of PyGetSetDef structures is used in the PyTypeObject.tp_getset slot.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
static PyObject*
Foo_property_getter(Foo* self, void * /* closure */) {
    return /* ... */;
}

int
Foo_property_setter(Foo* self, PyObject *value) {
    return /* 0 on success, -1 on failure with error set. */;
}

static PyGetSetDef Foo_properties[] = {
    {"id", (getter) Foo_property_getter, (setter) Foo_property_setter,
        "The property documentation.", NULL },
    {NULL}  /* Sentinel */
};

And the type struct must reference this array of PyMemberDef thus:

static PyTypeObject FooType = {
    /* ... */
    Foo_properties,             /* tp_getset */
    /* ... */
};

Reference to PyGetSetDef.