Skip to content
Advertisement

How to manage an object from a class defined in python using the C-Python API

I have two versions of a part of a program. One is written in C and the second one is in Python. The Python version has been developed much more than the C version but a critical function is slow and is already present in C.

Therefore I want to wrap the C-version using the C-Python API and import it in Python to improve the speed

But I don’t know how to parse objects from a class defined in Python, inside the C function.

The two classes defined in Python have many attributes:

class Py_input: #it will store the input data
    def__init__(self):
        selt.n1 = ...
        self.n2 = ...
        self.n3 = ...
        .
        .
        .
class Py_output: #it will store the output data
    def __init__(self):
        self.out1 = np.zeros(...)
        self.out2 = np.zeros(...)
        .
        .
        .

The function receives as input an object of py_input and stores the outputs in an object of py_output. I need to pass those objects to a C extension of Python written using the C – API such as in the example:

import c_fun

inp = Py_input()
out = Py_output()
c_fun.function(inp, out)

where the c_fun.so module has been generated by compiling the C code using GCC:

gcc -I/usr/include/Python3.8/ -shared -o c_fun.so -fPIC c_fun.c

In C all the attributes of the python classes are stored in structs.

The best solution I believe should be to parse the object inside the C code into the C-struct. My issue is that I don’t know how to parse a Python-generated class.

I have tried using PyObject_GetAttrString to parse the objects but I get an error. When I looked for the attribute using PyObject_HasAttrString it returns that there is no element named “n1”. such as:

static PyObject* py_function(PyObject* self, PyObject* args) {
  PyObject obj_in, obj_out;
  if (!PyArg_ParseTuple(args, "OO", &obj_in, & obj_out)) 
    return NULL;
  int a = PyObject_HasAttrString(&obj_in, "n1"); // it returns 0 so False
  .
  .
  .
}

Some other solutions that I have thought of: I unpack the class. such as:

c_fun.function(inp.n1, inp.n2, inp.n3,..., out.out1,...)

But that could risk having a confusing function and I could easily make errors.

I could create two custom Python types in C but that would mean adding a third copy of the same struct being the other two already integrated

Advertisement

Answer

The issue was PyObject obj_in, obj_out;

it should have been a pointer.

PyObject *obj_in;
PyObject *obj_out;

After fixing the pointers, PyObject_HasAttrString and PyObject_GetAttrString work fine.

Advertisement