Extending & Embedding Python Using C - Embedding
Written by Mike James   
Tuesday, 13 August 2024
Article Index
Extending & Embedding Python Using C - Embedding
Embedding Under Linux
Python or C?
Embedded Debugging

extendPython180

Python or C?

With Python embedded you have the choice of writing C to call Python functions or writing Python code to use the same functions behind the scenes. For example, we can call math.sqrt using API function or by running a Python program:

#define PY_SSIZE_T_CLEAN
#include <Python.h>
int main(int argc, char *argv[])
{
  Py_Initialize();
  PyObject *math =PyImport_ImportModule("math");
  PyObject *mathdict = PyModule_GetDict(math);
  PyObject *myFunction = 
PyDict_GetItemString(mathdict, "sqrt"); PyObject *args = Py_BuildValue("(I)", 2); PyObject *result =
PyObject_Call(myFunction, args, NULL); double res=PyFloat_AS_DOUBLE(result); printf("%f\n",res); PyRun_SimpleString( "import math\n" "print(math.sqrt(2))\n"); Py_FinalizeEx(); return 0; }

If you run this you will see:

1.414214
1.4142135623730951

The first value comes from loading the math module, looking up sqrt in its dict and then calling the function. To display the result we convert to a C double. The second value comes from running the equivalent Python program.

Getting Results From Python

A common question is how to get a return value from a Python program. The simple answer is you can’t. Python statements such as for, if and so on don’t return results. Only a Python expression such as 2*2 or a function returns a result. You can evaluate an expression and get a return value using one of the PyRun_String functions.

For example:

PyObject* _g = PyDict_New();;
PyObject* _l = PyDict_New();
PyObject *pyResult= PyRun_String( 
"2+2",Py_eval_input, _g, _l); int Cresult=PyLong_AS_LONG(pyResult); printf(“%d\n”,Cresult);

The Py_eval_input makes PyRun_String evaluate an expression. The two dicts specify a global and local namespace of variables that can be used in the expression. For example, if we wanted to add X and Y:

PyObject* g = PyDict_New();
PyObject* l = PyDict_New();
PyDict_SetItemString(l,"X",PyLong_FromLong(2));
PyDict_SetItemString(l,"Y",PyLong_FromLong(2));
PyObject *pyResult= PyRun_String( "X+Y",Py_eval_input,
g, l); int Cresult=PyLong_AS_LONG(pyResult); printf(“%d\n”,Cresult);

The main use of the global namespace is to allow the expression to use imported modules. For example to call math.sqrt you would use:

PyObject* g = PyDict_New();
PyObject* l = PyDict_New();
PyObject *math =PyImport_ImportModule("math");
PyDict_SetItemString(g, "math",math);
PyObject *pyResult= PyRun_String( "math.sqrt(2)",
Py_eval_input, g, l); double res2=PyFloat_AS_DOUBLE(pyResult); printf("%f\n",res2);

Notice that we have to load the math module and then make it available for the expression to use.

The full program can be seen on the book’s webpage.

In a more general case, you can simply add a function that returns a result and runs it in the usual way, see the implementation of the Pi function at the start of the chapter.



Last Updated ( Tuesday, 13 August 2024 )