Calling a Python Method from C/C++, and Extracting Its Return Value

Calling a python method from C/C++, and extracting its return value

As explained before, using PyRun_SimpleString seems to be a bad idea.

You should definitely use the methods provided by the C-API (http://docs.python.org/c-api/).

Reading the introduction is the first thing to do to understand the way it works.

First, you have to learn about PyObject that is the basic object for the C API. It can represent any kind of python basic types (string, float, int,...).

Many functions exist to convert for example python string to char* or PyFloat to double.

First, import your module :

PyObject* myModuleString = PyString_FromString((char*)"mytest");
PyObject* myModule = PyImport_Import(myModuleString);

Then getting a reference to your function :

PyObject* myFunction = PyObject_GetAttrString(myModule,(char*)"myabs");
PyObject* args = PyTuple_Pack(1,PyFloat_FromDouble(2.0));

Then getting your result :

PyObject* myResult = PyObject_CallObject(myFunction, args)

And getting back to a double :

double result = PyFloat_AsDouble(myResult);

You should obviously check the errors (cf. link given by Mark Tolonen).

If you have any question, don't hesitate. Good luck.

Call C++ function from python and get return value

If you use the readelf -Ws on your so file, it will give you items inside your so library:

FUNC GLOBAL DEFAULT 12 _Z9getStringB5cxx11v

You will see that your function is in fact there, it just has a mangled name.
So proper name for calling ctype on the library would be _Z9getStringB5cxx11v().

However there are still few things wrong with it.
Mark your method as an extern to let compiler know it has external linkage:

extern string getString()

Alternatively if you want to use it as getString() you can mark it as extern "C" which will disable c++ mangler

extern "C" string getString()

But in either case I think you will find that you have some memory problems. I think the proper way would be to return c style pointer to a character array and memory manage it yourself, something like this should work:

strfunc.cpp:

#include <iostream>
#include <string>

using namespace std;

char hostname[] = "test.stack.com";

extern "C" char * getString()
{

return hostname;

}

strfunc.py:

#!/usr/bin/env python
from ctypes import *

test=cdll.LoadLibrary("./strfunc.so")
test.getString.restype=c_char_p
print(test.getString())

In case of string I think you need to figure out how to manage memory and return types properly to let know to the python that you are actually passing string. It might be doable but not so easy as the above.

Python C API: problems with calling python c method in c

You must create a PyTuple as second argument of your own function(st_div_r)!

There are 2 main ways to do that!

First Way

PyObject *first_list = PyList_GetItem(pList, 0)
//PyObject *divider = Py_BuildValue("d", d)

//PyObject *tuple_with_list_and_divider = Py_BuildValue("(Od)", first_list, divider);

PyObject *tuple_with_list_and_divider = Py_BuildValue("(Od)", first_list, d);

PyObject *list_after_division = st_div_r(pList, tuple_with_list_and_divider)

PyList_SetItem(pList , 0, list_after_division);

Second Way

PyObject *first_list = PyList_GetItem(pList, 0)
PyObject *divider = Py_BuildValue("d", d)

PyObject *tuple_with_list_and_divider = PyTuple_New(2);

PyTuple_SetItem(tuple_with_list_and_divider, 0, first_list);
PyTuple_SetItem(tuple_with_list_and_divider, 1, divider);

PyObject *list_after_division = st_div_r(pList, tuple_with_list_and_divider)

PyList_SetItem(pList , 0, list_after_division);

In first example I forgot that Py_BuildValue converts d to Py_Double.

Sorry for my Bad English!

Extracting value from Python after it's embedded in C++

I have actually figured out how to do that myself. There is no need to use eval() in order to extract the result of the execution of the function. Instead, you can do the following:

#include <Python.h>
#include <iostream>

int main() {
// Initialize Python
Py_Initialize();

// Create a function
PyRun_SimpleString("f = lambda x: x * 2 - 3");

// Import __main__ where the f is stored
PyObject *main = PyImport_ImportModule("__main__");
PyObject *function = PyObject_GetAttrString(main, "__function");

// Create an argument tuple for the function
PyObject * args = PyTuple_New(1);
PyObject * first_argument = PyInt_FromLong(10);
PyTuple_SetItem(args, 0, first_argument);

// Call the function and get its result
PyObject * result = PyObject_CallObject(function, args);

// Output the result
cout << PyInt_AsLong(result) << endl;

// Destroy Python frame
Py_Finalize();
}

However, I am still curious why eval did not work as shown in my original question

Calling python hello world function from C, parsing string arguments

The sample code is parsing the arguments as integers, buy you've passed a string. atoi("world") returns 0, so that's the integer you get:

/* Create tuple of the correct length for the arguments. */
pArgs = PyTuple_New(argc - 3);
for (i = 0; i < argc - 3; ++i) {
/* Convert each C argv to a C integer, then to a Python integer. */
pValue = PyInt_FromLong(atoi(argv[i + 3]));
if (!pValue) {
Py_DECREF(pArgs);
Py_DECREF(pModule);
fprintf(stderr, "Cannot convert argument\n");
return 1;
}
/* iValue reference stolen here: */
/* Store the Python integer in the tuple at the correct offset (i) */
PyTuple_SetItem(pArgs, i, pValue);
}

Change the conversion line to the following to handle any string:

pValue = PyString_FromString(argv[i + 3]);

Running and obtaining results of a python program in C

You can do like this to call the python file from the C program:

char command[50] = "python full_path_name\\file_name.py";

system(command);

This piece of code worked for me...

I didn't use # include < python2.7/Python.h>

You can write the results from the python file to any text file and then use the results stored in the text file to do whatever you want to do...

You can also have a look at this post for further help:

Calling python script from C++ and using its output



Related Topics



Leave a reply



Submit