pythonccpythonpython-extensions

Interfacing a cpython extension with a C struct


I am trying to create a python extension to interface python with my C software. Mainly I need to made a big struct from C software accessible and modifiable in python, so I would like to create a Python class to do the intermediate, eg so that doing in python my_class.var_int = 1 would be reflected on the subjacent struct.

So I made a simple Python object, with the following subjactent data

typedef struct {
    PyObject_HEAD
    struct my_struct *struct_data; 
} CustomObject;

The problem is that with this method I need to define a getter and setter function for each field in my struct, which is huge (~300) even if there are mainly primitive fields such as int or double. And writing that many function will be error-prone and not very evolutive.

There is the simple method to define class member stored directly from in the Object struct :

static PyMemberDef Custom_members[] = {
    {"var_int1", T_INT, offsetof(CustomObject, var_int1), 0,
     "first name"},
    {"var_int2", T_int, offsetof(CustomObject, var_int2), 0,
     "last name"},
    {"var_double", T_DOUBLE, offsetof(CustomObject, var_doube), 0,
     "custom number"},
    {NULL}  
};

But in my case it won't work since the variables are not stored directly in the Object struct, but in a struct referenced by the Object.

Is there any simpler way to interface a struct with Python. Or am I stuck to define a getter and setter function for each of my struct field ?


Solution

  • In order to be able to use PyMemberDef you need to change the memory layout of your class (struct_data is no longer pointer):

    typedef struct {
        PyObject_HEAD
        struct my_struct struct_data; 
    } CustomObject;
    

    and now offsetof can be used again:

    static PyMemberDef Custom_members[] = {
        {"var_int1", T_INT, offsetof(CustomObject, struct_data.var_int1), 0,
         "first name"},
         ...
        {NULL}  
    };
    

    As the offset in the PyMemberDef-definition should be the same for all instances of class CustomObject, it cannot depend on the address stored in the pointer struct_data.

    So if there is no really good reason, why struct_data must be a pointer, the above solution has multiple advantages (less code, no memory management needed and so on).