I am new to the Python/C API and while I got some basic functions to work, I am struggling with this one.
PyObject* sum_elements(PyObject*, PyObject *o)
{
Py_ssize_t n = PyList_Size(o);
long total = 0;
if (n < 0)
{
return PyLong_FromLong(total);
}
PyObject* item;
for (int i = 0; i < n; i++)
{
item = PyList_GetItem(o, i);
if (!PyLong_Check(item)) continue;
total += PyLong_AsLong(item);
}
return PyLong_FromLong(total);
}
Basically this is the function from the introduction on the doc page. It should receive a python list and return the sum of all elements. The function works fine if i pass a list, if I pass something else however i get the error message
SystemError: c:\_work\5\s\objects\listobject.c:187: bad argument to internal function
This situation should be handled by the if (n<0)
statement, as n is -1 if the passed object is not a list.
I am binding the function the following way:
static PyMethodDef example_module_methods[] = {
{ "sum_list", (PyCFunction)sum_elements, METH_O, nullptr},
{ nullptr, nullptr, 0, nullptr }
};
Thanks.
The error
SystemError: c:\_work\5\s\objects\listobject.c:187: bad argument to internal function
is actually occurs at
Py_ssize_t n = PyList_Size(o)
Because PyList_Size
has an extra check to see whether the object of list type, If not it will call PyErr_BadInternalCall
to raise the SystemError
. See the implementation of PyList_Size
in listobject.c
PyList_Size(PyObject *op)
{
if (!PyList_Check(op)) {
PyErr_BadInternalCall();
return -1;
}
else
return Py_SIZE(op);
}
The PyErr_BadInternalCall
is a shorthand for PyErr_SetString(PyExc_SystemError, message)
, where message indicates that an internal operation (e.g. a Python/C API function) was invoked with an illegal argument.
You should use PyList_Check
API to check whether the object is of list
type . As per the doc it Return true if object is a list object or an instance of a subtype of the list type.
PyObject* sum_elements(PyObject*, PyObject *o)
{
// Check if `o` is of `list` type, if not raise `TypeError`.
if (!PyList_Check(o)) {
PyErr_Format(PyExc_TypeError, "The argument must be of list or subtype of list");
return NULL;
}
// The argument is list type, perform the remaining calculations.
Py_ssize_t n = PyList_Size(o);
long total = 0;
if (n < 0)
{
return PyLong_FromLong(total);
}
PyObject* item;
for (int i = 0; i < n; i++)
{
item = PyList_GetItem(o, i);
if (!PyLong_Check(item)) continue;
total += PyLong_AsLong(item);
}
return PyLong_FromLong(total);
}
Once this extra check is added, the function call will raise
TypeError: The argument must be of list or sub type of list
when the argument other than list
type is supplied.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With