I need to make a call from C++ to a Python function of the form
def function(a, b, *c)
    print(a) # Mock example
    print(b) # Mock example
    print(c) # Mock example
Requirement: I shouldn’t modify the Python function. They are provided by users and should have that signature for consistency.
The Python.h interface provides (quoting from the link to not make you have to open another page):
- PyObject* PyObject_CallFunction(PyObject *callable, const char *format, ...)Return value: New reference. Call a callable Python object callable, with a variable number of C arguments. The C arguments are described using a Py_BuildValue() style format string. The format can be NULL, indicating that no arguments are provided. Return the result of the call on success, or raise an exception and return NULL on failure. This is the equivalent of the Python expression: callable(*args). Note that if you only pass PyObject * args, PyObject_CallFunctionObjArgs() is a faster alternative.
- PyObject* PyObject_CallFunctionObjArgs(PyObject *callable, ..., NULL)Return value: New reference. Call a callable Python object callable, with a variable number of PyObject* arguments. The arguments are provided as a variable number of parameters followed by NULL. Return the result of the call on success, or raise an exception and return NULL on failure. This is the equivalent of the Python expression: callable(arg1, arg2, …)
The number of arguments passed as part of c is not known at compilation time. At run time I have them as a PyObject * (let’s call it cc) that points to a tuple. Let’s say that the input for a I have it as a PyObject * called ca, likewise cb for b and that a PyObject * called cfunction holds the reference to function.
How can I make this call?
I have tried:
- PyObject_CallFunctionObjArgs(cfunction, ca, cb, cc)and similarly with the other method passing the- formatstring. But this seems to cause what in Python would be a call of the form- function(a, b, (c,)). Inside the Python code the- c, instead of being a tuple of the values that I had in- ccis a 1-element tuple with first entry being the tuple of elements that I had in- cc.
- I also tried creating a new - PyObject *- cd, specifically a- PyTupleObjectcontaining as first two elements the content of- caand- cband the remaining elements being the elements of- cc. Then I made a call like- PyObject_CallFunctionObjArgs(cfunction, cd). But this time Python complains that- functionrequires the positional argument- b. I assume because the tuple in- cdis being given entirely to- a.
Advertisement
Answer
The following worked:
PyObject_CallFunctionObjArgs(cfunction, ca, cb, cc, NULL)
It produced the equivalent of a call in Python to
function(a,b,*c)