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 theformat
string. 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 incc
is 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 aPyTupleObject
containing as first two elements the content ofca
andcb
and the remaining elements being the elements ofcc
. Then I made a call likePyObject_CallFunctionObjArgs(cfunction, cd)
. But this time Python complains thatfunction
requires the positional argumentb
. I assume because the tuple incd
is 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)