In this article, we will mainly focus on safe execution of a Python callable from C, returning a result back to C and writing C code that needs to access a Python function as a callback.
The code below focuses on the tricky parts that are involved in calling Python from C.
Code #1 : [Step 1 and 2] Own the GIL and Verify that function is a proper callable
#include <Python.h>
double call_func(PyObject *func, double x, double y)
{
PyObject *args;
PyObject *kwargs;
PyObject *result = 0;
double retval;
PyGILState_STATE state = PyGILState_Ensure();
if (!PyCallable_Check(func))
{
fprintf (stderr, "call_func: expected a callable\n" );
goto fail;
}
|
Code #2 : Building Arguments, calling function, Check for Python exceptions
Create the return value, Restore previous GIL state and return.
args = Py_BuildValue( "(dd)" , x, y);
kwargs = NULL;
result = PyObject_Call(func, args, kwargs);
Py_DECREF(args);
Py_XDECREF(kwargs);
if (PyErr_Occurred())
{
PyErr_Print();
goto fail;
}
if (!PyFloat_Check(result))
{
fprintf (stderr, "call_func: callable didn't return a float\n" );
goto fail;
}
retval = PyFloat_AsDouble(result);
Py_DECREF(result);
PyGILState_Release(state);
return retval;
fail:
Py_XDECREF(result);
PyGILState_Release(state);
abort ();
}
|
A reference to an existing Python callable needs to be passed in, to use this function. To do that there are many ways like – simply writing C code to extract a symbol from an existing module or having a callable object passed into an extension module.
The code given below shows calling a function from an embedded Python interpreter.
Code #3 : Loading a symbol from a module
#include <Python.h>
PyObject *import_name( const char *modname, const char *symbol)
{
PyObject *u_name, *module;
u_name = PyUnicode_FromString(modname);
module = PyImport_Import(u_name);
Py_DECREF(u_name);
return PyObject_GetAttrString(module, symbol);
}
|