Search code examples
pythonc++python-embedding

Embedding python into C++ does not work as expected


I am embedding Python into a C++ application.

When I run the following piece of C++ code, which returns me the timestamp, it works fine.

Py_Initialize();    

std::string strModule = "time"; // module to be loaded
pName = PyString_FromString(strModule.c_str());
pModule = PyImport_Import(pName); // import the module

pDict = PyModule_GetDict(pModule); // get all the symbols in the module
pFunc = PyDict_GetItemString(pDict, "time"); // get the function we want to call

// Call the function and get the return in the pValue
pValue = PyObject_CallObject(pFunc, NULL);
if (pValue == NULL){
    printf('Something is wrong !');
    return 0;
}
printf("Return of python call : %d\n", PyInt_AsLong(pValue)); // I get the correct timestamp

Py_Finalize();

Now I want to get the sys.path. But the similar code throws me error:

Py_Initialize();    

std::string strModule = "sys"; // module to be loaded
pName = PyString_FromString(strModule.c_str());
pModule = PyImport_Import(pName); // import the module

pDict = PyModule_GetDict(pModule); // get all the symbols in the module
pFunc = PyDict_GetItemString(pDict, "path"); // get the function we want to call

// Call the function and get the return in the pValue
pValue = PyObject_CallObject(pFunc, NULL);
if (pValue == NULL){
    printf('Something is wrong !'); // I end up here, why pValue is NULL?
    return 0;
}
printf("Return of python call : %d\n", PyInt_AsLong(pValue));

Py_Finalize();

I guess the problem is that time.time() is a function call whereas sys.path is a variable. If that is the case:

  1. How to get the result of a variable?
  2. How to properly translate the result (in this case a list) to something meaningful in C++ for e.g. an array of strings?

If not, how to proceed? I am using Python 2.7.6

Thanks.


Solution

  • Your problem is that PyDict_GetItemString(pDict, "path") will return python list and it is not callable. And when you execute PyObject_CallObject(pFunc, NULL); you will execute it. This is equal to sys.path().

    This should work:

    PyObject *pName, *pModule, *pDict, *list, *pValue, *item;
    int n, i;
    char *name;
    Py_Initialize();    
    
    std::string strModule = "sys"; // module to be loaded
    pName = PyString_FromString(strModule.c_str());
    pModule = PyImport_Import(pName); // import the module
    
    pDict = PyModule_GetDict(pModule); // get all the symbols in the module
    list = PyDict_GetItemString(pDict, "path"); // get python list
    n = PyList_Size(list);
    if (n < 0)
        return -1; /* Not a list */
    
    for (i = 0; i < n; i++) { // iterate over list
        item = PyList_GetItem(list, i); /* Can't fail */
        if (!PyString_Check(item)) continue; /* Skip non-string */
        name = PyString_AsString(item);
        std::puts(name);
    }
    
    
    Py_Finalize();
    return 0;
    

    Full code here.