I am trying to pass a list to python from cpp and taking it back. Initially I tried to pass a single value and get back one value. It worked. Now I am trying to pass the complete array/list Below is my cpp code:
#include <iostream>
#include <Python.h>
#include <numpy/arrayobject.h>
#include <typeinfo>
using namespace std;
int main()
{
Py_Initialize();
PyObject *sys = PyImport_ImportModule("sys");
PyObject *path = PyObject_GetAttrString(sys, "path");
PyList_Append(path, PyString_FromString("."));
PyObject *pName, *pModule, *pDict, *pFunc, *pArgs, *pValue;
// Build the name object
pName = PyString_FromString("mytest");
// Load the module object
pModule = PyImport_Import(pName);
// pDict is a borrowed reference
pDict = PyModule_GetDict(pModule);
// pFunc is also a borrowed reference
pFunc = PyObject_GetAttrString(pModule, "stuff");
if (!PyCallable_Check(pFunc))
PyErr_Print();
PyObject *list = PyList_New (5);
Py_ssize_t size = PyList_GET_SIZE(list);
for(Py_ssize_t s = 0; s < size; s++ )
{
PyList_SetItem(list, s, Py_BuildValue("d", 2.5));
}
PyObject* result = PyObject_CallObject(pFunc, list);
if(result==NULL)
{cout << "FAILED ..!!" << endl;}
cout << result << endl;;
return 0;
}
I am always getting "FAILED..!!".
Here is my mytest.py
def stuff(a):
x=a
return x
Any suggestions where I might be going wrong?
From the documentation:
PyObject* PyObject_CallObject(PyObject *callable, PyObject *args)
This is the equivalent of the Python expression: callable(*args).
Whereas PyObject_CallFunctionObjArgs is documented as:
PyObject* PyObject_CallFunctionObjArgs(PyObject *callable, ..., NULL)
This is the equivalent of the Python expression: callable(arg1, arg2, ...).
So change your call to the following:
PyObject* result = PyObject_CallFunctionObjArgs(pFunc, list, NULL);
(or you could wrap your list inside another list and keep on using CallObject, but this is by far the easier solution)
Related
From reading another post, I am trying to embbed some some Python code into C:
main.c
#include <Python.h>
int callModuleFunc(int array[], size_t size) {
PyObject *mymodule = PyImport_ImportModule("py_function");
PyObject *myfunc = PyObject_GetAttrString(mymodule, "printlist");
PyObject *mylist = PyList_New(size);
for (size_t i = 0; i != size; ++i) {
PyList_SET_ITEM(mylist, i, PyInt_FromLong(array[i]));
}
PyObject *arglist = Py_BuildValue("(o)", mylist);
PyObject *result = PyObject_CallObject(myfunc, arglist);
int retval = (int)PyInt_AsLong(result);
Py_DECREF(result);
Py_DECREF(arglist);
Py_DECREF(mylist);
Py_DECREF(myfunc);
Py_DECREF(mymodule);
return retval;
}
int main(int argc, char *argv[])
{
int a[] = {1,2,3,4};
callModuleFunc(a, 4);
return 0;
}
py_function.py
'''py_function.py - Python source designed to '''
'''demonstrate the use of python embedding'''
def printlist(mylist):
print mylist
Then I compiled with:
gcc main.c -I/usr/include/python2.7 -lpython2.7
But then I ran the app, it gives me a segmentation fault error:
/a.out
[1] 18890 segmentation fault ./a.out
Is there something that I am missing?
There were several problems with your code:
Py_Initialize() was not called.
PyImport_ImportModule() failed to find your python file, since in embedded Python you start without an initial module, relative to which the search can work. The fix is to explicitly include the current directory in sys.path.
"(O)" in Py_BuildValue() should use a capital 'O'.
The printlist function should return a value (since that is what the C-code expects).
This should work:
main.c
#include <Python.h>
void initPython()
{
Py_Initialize();
PyObject *sysmodule = PyImport_ImportModule("sys");
PyObject *syspath = PyObject_GetAttrString(sysmodule, "path");
PyList_Append(syspath, PyString_FromString("."));
Py_DECREF(syspath);
Py_DECREF(sysmodule);
}
int callModuleFunc(int array[], size_t size) {
PyObject *mymodule = PyImport_ImportModule("py_function");
assert(mymodule != NULL);
PyObject *myfunc = PyObject_GetAttrString(mymodule, "printlist");
assert(myfunc != NULL);
PyObject *mylist = PyList_New(size);
for (size_t i = 0; i != size; ++i) {
PyList_SET_ITEM(mylist, i, PyInt_FromLong(array[i]));
}
PyObject *arglist = Py_BuildValue("(O)", mylist);
assert(arglist != NULL);
PyObject *result = PyObject_CallObject(myfunc, arglist);
assert(result != NULL);
int retval = (int)PyInt_AsLong(result);
Py_DECREF(result);
Py_DECREF(arglist);
Py_DECREF(mylist);
Py_DECREF(myfunc);
Py_DECREF(mymodule);
return retval;
}
int main(int argc, char *argv[])
{
initPython();
int a[] = {1,2,3,4,5,6,7};
callModuleFunc(a, 4);
callModuleFunc(a+2, 5);
Py_Finalize();
return 0;
}
py_function.py
'''py_function.py - Python source designed to '''
'''demonstrate the use of python embedding'''
def printlist(mylist):
print mylist
return 0
C PART
#include <stdlib.h>
#include <iostream>
#include "Python.h"
using namespace std;
char* PyCall(const char* a, const char* b, const char* c) {
Py_Initialize();
if (!Py_IsInitialized())
{
}
PyRun_SimpleString("import sys");
PyRun_SimpleString("sys.path.append('./')");
PyObject* pFunc1 = NULL;
PyObject* pFunc2 = NULL;
PyObject* pFunc3 = NULL;
PyObject* pModule = PyImport_ImportModule(a);
if (pModule == NULL)
{
cout << "notfind";
}
pFunc3 = PyObject_GetAttrString(pModule, b);
PyObject* args3 = PyTuple_New(1);
PyObject* args2 = PyBytes_FromString(c);
PyTuple_SetItem(args3, 0, args2);
PyObject* pRet = PyObject_CallObject(pFunc3, args3);
char* result = NULL;
if (pRet)
{
result = PyBytes_AsString(pRet);
}
return result;
}
int main()
{
char* res = PyCall("mytest", "codetest", "{'title':'Task Manager'}");
cout << res;
}
Python Part
def codetest(title):
import win32gui
import win32api
import json
dic = json.loads(title)
a = win32gui.FindWindow(None,dic["title"])
return str(a)
The basic Python library was imported successfully, but a runtime error occurred
enter image description here
Exception thrown at 0x00007ff680271103 (in pycode. Exe): 0xc0000005: an access violation occurred while reading location 0x000000000000000.
This problem has been resolved. The problem of the return value during the call resulted in cout error, and the parameter passed in python is bytes that needs to be decoded and transcoded. I didn’t read the C-API documentation carefully.
I want to call the Python function in C++ using python.h but there are some problems.
Here is my Python function sample
def function1(tuple1, tuple2, string1, string2 ,string3, double1, string4 = ""):
...
and the C++ sample
double function_adapter(const vector<double> &vec1, const vector<double> &vec2, const string &string1, const string &string2, const string &string3, const double double1, const string &string4)
{
Py_Initial();
PyRun_SimpleString("import sys");
PyRun_SimpleString("sys.path.append(\"./\")");
PyObject *pModule, *pFunc, *pRes;
pModule = PyImport_Import(PyString_FromString("PythonFile"));
pFunc = PyObject_GetAttrString(pModule, "function1");
PyObject *pArgs = PyTuple_New(7);
PyObject *pVec1 = PyTuple_New(vec1.size());
for(size_t i = 0; i < vec1.size(); ++i) {
PyTuple_SetItem(pVec1, i, Py_BuildValue("f", vec1[i]));
}
PyObject *pVec2 = PyTuple_New(vec2.size());
for(size_t i = 0; i < vec2.size(); ++i) {
PyTuple_SetItem(pVec2, i, Py_BuildValue("f", vec2[i]));
}
PyObject *pString1 = Py_BuildValue("s", string1);
PyObject *pString2 = Py_BuildValue("s", string2);
PyObject *pString3 = Py_BuildValue("s", string3);
PyObject *pDouble1 = Py_BuildValue("f", double1);
PyObject *pString4 = Py_BuildValue("s", string4);
PyTuple_SetItem(pArgs, 0, pVec1);
PyTuple_SetItem(pArgs, 1, pVec2);
PyTuple_SetItem(pArgs, 2, pString1);
PyTuple_SetItem(pArgs, 3, pString2);
PyTuple_SetItem(pArgs, 4, pString3);
PyTuple_SetItem(pArgs, 5, pDouble1);
PyTuple_SetItem(pArgs, 6, pString4);
pRes = PyObject_CallObject(pFunc, pArgs);
if(pRes == NULL) {
return -2;
}
int res = PyLong_AsLong(pRes);
Py_DecRef(pModule);
.
.
.
Py_Finalize();
return res;
}
But the pRes returns NULL. And the PyObject_CallObject is just like a blackbox, I can't step in to look how it works.
So I want to ask that is there anything wrong in my code?
And the arguments preparation is right or not? (There are few examples in this case on the internet.)
A CPython API function that returns NULL means that an error has occurred. You can use the PyErr_* set of API functions to query this exception.
For debugging, the most useful is probably PyErr_Print(), which will just print the exception and stack trace (if any) to stderr.
Make sure to double check that pModule and pFunc are not NULL. The exception may have occurred when trying to import the module or get the function from the module. CPython does not raise exceptions, it just returns NULL on an error. So checking the return value of C-API functions is important.
I am looking to pass an array from C++ to Python using C-API. By looking at various topics here, I came to know that I should be using PyArray_SimpleNewFromData method. When I am trying to implement on a very small array, I am getiing a segmentation fault in my code which I am not able to detect. Can anyone help me with this issue?
C++ code :
void init_numpy()
{
import_array();
}
int main(int argc, char *argv[])
{
PyObject *pName, *pModule, *pDict, *pFunc, *pValue, *pArgs, *pXVec, *xarr1;
PyObject *c ;
PyObject *pValue1 ;
int fArray[2] = {10,1} ;
PyObject *p = NULL ;
npy_intp m1 = 2;
Py_Initialize();
PySys_SetArgv(argc, argv);
init_numpy();
pName = PyString_FromString(argv[1]);
pModule = PyImport_Import(pName);
printf("check0\n");
pDict = PyModule_GetDict(pModule);
printf("check1\n");
pFunc = PyDict_GetItemString(pDict, argv[2]);
printf("check2\n");
c = PyArray_SimpleNewFromData(1,&m1,NPY_INT,fArray);
printf("check3\n");
pArgs = PyTuple_New(1);
PyTuple_SetItem(pArgs,0,c);
pValue = PyObject_CallObject(pFunc, pArgs);
if (pArgs != NULL)
{
Py_DECREF(pArgs);
}
// Clean up
Py_DECREF(pModule);
Py_DECREF(pName);
// Finish the Python Interpreter
Py_Finalize();
return 0;
}
Python Code:
import numpy as np
import scipy.io
def main(a):
print a
Output on verbose :
check0
check1
check2
Segmentation fault (core dumped)
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:
How to get the result of a variable?
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.
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.