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 theformatstring. But this seems to cause what in Python would be a call of the formfunction(a, b, (c,)). Inside the Python code thec, instead of being a tuple of the values that I had inccis a 1-element tuple with first entry being the tuple of elements that I had incc.I also tried creating a new
PyObject *cd, specifically aPyTupleObjectcontaining as first two elements the content ofcaandcband the remaining elements being the elements ofcc. Then I made a call likePyObject_CallFunctionObjArgs(cfunction, cd). But this time Python complains thatfunctionrequires the positional argumentb. I assume because the tuple incdis being given entirely toa.
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)