Reputation: 43
it's ok to pass a tuple as argument of a method, but as soon as I want to pass the tuple to a method of a class it doesn't work(I get a Run Failed at the row "ret = PyEval_CallObject(method,args);" thanks a lot if someone knows why it doesn't work
the following code used is:
enter code Python Code:
class cVector:
def __init__(self,msg):
self.value = msg
def ComputeNorm(self,vecData):
#don't use vecData for instance
result = 12.
return(result)
enter C++ Code
PyObject *ret, *mymod, *pclass, *method, *args, *object;
float retValue;
Py_Initialize();
PySys_SetPath(".");
// Module
mymod = PyImport_ImportModule("mModule8");
if (mymod == NULL){
cout << "Can't Open a module:\n" ;
Py_DECREF(mymod);
}
// Class
pclass = PyObject_GetAttrString(mymod, "cVector");
if (pclass == NULL) {
Py_DECREF(pclass);
cout << "Can't find class\n";
}
// Parameters/Values
args = Py_BuildValue("(f)", 100.0);
if (args == NULL) {
Py_DECREF(args);
cout << "Can't build argument list for class instance\n";
}
// Object with parameter/value
object = PyEval_CallObject(pclass, args);
if (object == NULL) {
Py_DECREF(object);
cout << "Can't create object instance:\n";
}
// Decrement the argument counter as we'll be using this again
Py_DECREF(args);
// Get the object method - note we use the object as the object
// from which we access the attribute by name, not the class
method = PyObject_GetAttrString(object, "ComputeNorm");
if (method == NULL) {
Py_DECREF(method);
cout << "Can't find method\n";
}
// Decrement the counter for our object, since we now just need
// the method reference
Py_DECREF(object);
// Build our argument list - an empty tuple because there aren't
// any arguments
cout << "Prepare the Tuple:\n" ;
// WE pass a tuple
args = PyTuple_New( 3 );
if (args == NULL) {
Py_DECREF(args);
cout << "Can't build argument list for method call\n";
}
PyObject *py_argument;
// 1st argument
py_argument = PyFloat_FromDouble(5.);
PyTuple_SetItem(args, 0, py_argument);
// 2nd argument
py_argument = PyFloat_FromDouble(10.);
PyTuple_SetItem(args, 1, py_argument);
// 3nd argument
py_argument = PyFloat_FromDouble(15.);
PyTuple_SetItem(args, 2, py_argument);
cout << "Before the Exec:\n" ;
// Call our object method with arguments
ret = PyEval_CallObject(method,args);
//ret = PyObject_CallObject(method,args);
if (ret == NULL) {
Py_DECREF(ret);
cout << "Couldn't call method\n";
}
// Convert the return value back into a C variable and display it
PyArg_Parse(ret, "f", &retValue);
printf("RetValue: %f\n", retValue);
// Kill the remaining objects we don't need
Py_DECREF(method);
Py_DECREF(ret);
// Close off the interpreter and terminate
Py_Finalize();
Upvotes: 1
Views: 1711
Reputation: 9041
You don't show how you obtain method
. You have to get it from an instance for this to work (here I assume that inst
is a PyObject*
pointing to an instance of cVector
class):
PyObject *method = PyObject_GetAttrString(inst, "ComputeNorm");
Always check for errors:
if (method == NULL)
return NULL;
(or do other appropriate thing, depending on the context)
Then, your code can be greatly shortened:
PyObject *args = Py_BuildValue("(ddd)", 5.0, 10.0, 15.0);
(this creates a tuple with three Python floats made from C doubles)
or even combined with the call:
PyObject *ret = PyObject_CallFunction(method, "(ddd)", 5.0, 10.0, 15.0);
You call even combine everything in one call:
PyObject *ret = PyObject_CallMethod(inst, "ComputeNorm",
"(ddd)", 5.0, 10.0, 15.0);
Again, remeber to check for errors:
if (ret == NULL)
return NULL;
And always decref all the objects you create and don't need anymore (otherwise you will be leaking memory):
Py_DECREF(ret);
(assuming you've used the PyObject_CallMethod
, otherwise you might have to decref args
and method
as well)
Upvotes: 2