1

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();  
1
  • 1
    "it doesn't work" is really uninformative. What's wrong? Also, how do you initialize args? Can't check this right now, but remember that tuples are immutable and you can only PyTuple_SetItem as many items as you declared in PyTuple_New. Also, have you tried, maybe, PyObject_CallFunction, which supports a nice, PyObject_BuildValue-style of building a tuple right in place? Commented Jan 9, 2012 at 12:01

1 Answer 1

2

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)

Sign up to request clarification or add additional context in comments.

6 Comments

thank you for your short reply Sorry I didn't put the complete code (method,class initialization) as I think it works,the code is the following (I want to "dynamically' initialize the tuple in c++
thanks again for your fast reply, I can't put the code online before 6 hours time (constraint from stackoverflow for a first time subscriber)I 'll do it soon
your solution doesn't match with my need which is to feed a tuple with many elements from database.the piece of code works in this case,but it works with a direct method in a module file and not with a method in a class.
You'll have to be more specific than "doesn't work" (post all relevant code, say what happens, say what did you expect, post complete error messages, etc.).
thanks Yak, I will do what you day after the 6 hours required by stackoverflow (a new subscriver can't post a new message immediatly he has to wait 6 hours;
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.