I've been struggling to have some generic method of iterating over a sequence or iterable in the Cpython C API. The example code below compiles without errors, but fails when run as follows:
it ok
Segmentation fault: 11
I'm speculating that it's failing at the while ((item = PyIter_Next(it)))
line but this is hardly controversial since the equivalent python is pretty standard:
x = [1,2,3]
it = iter(x)
for i in it:
print(i)
Clearly, I'm doing something wrong with the c equivalent. Any help or guidance would be most appreciated!
#define PY_SSIZE_T_CLEAN
#include <Python.h>
int
main(int argc, char *argv[])
{
wchar_t *program = Py_DecodeLocale(argv[0], NULL);
if (program == NULL) {
fprintf(stderr, "Fatal error: cannot decode argv[0]\n");
exit(1);
}
Py_SetProgramName(program);
Py_Initialize();
// create list
PyObject *list = PyList_New(2);
PyObject *n1 = PyLong_FromLong(1);
PyObject *n2 = PyLong_FromLong(2);
PyList_Append(list, n1);
PyList_Append(list, n2);
PyObject *it = PyObject_GetIter(list);
PyObject *item;
int i = 0;
if (it) {
printf("it ok\n");
while ((item = PyIter_Next(it))) {
if (PyLong_Check(item)) {
i++;
long long_item = PyLong_AsLong(item);
printf("%d long: %ld", i, long_item);
} else if PyFloat_Check(item) {
i++;
float float_item = PyFloat_AsDouble(item);
printf("%d float: %f", i, float_item);
} else if PyUnicode_Check(item) {
i++;
const char *unicode_item = PyUnicode_AsUTF8(item);
printf("%d unicode: %s", i, unicode_item);
} else continue;
Py_DECREF(item);
Py_DECREF(it);
}
} else {
if (PyErr_Occurred()) {
PyErr_Print();
}
Py_DECREF(n1);
Py_DECREF(n2);
Py_DECREF(list);
if (Py_FinalizeEx() < 0) {
exit(120);
}
PyMem_RawFree(program);
return 0;
}
}
In response to @DavidW's helpful observation of my error, here is the corrected code which could perhaps be a helpful example to others.
#define PY_SSIZE_T_CLEAN
#include <Python.h>
int
main(int argc, char *argv[])
{
wchar_t *program = Py_DecodeLocale(argv[0], NULL);
if (program == NULL) {
fprintf(stderr, "Fatal error: cannot decode argv[0]\n");
exit(1);
}
Py_SetProgramName(program);
Py_Initialize();
// create list
PyObject *list = PyList_New(0); // empty list
PyObject *n1 = PyLong_FromLong(10);
PyObject *n2 = PyLong_FromLong(20);
PyList_Append(list, n1);
PyList_Append(list, n2);
PyObject *iter;
PyObject *item;
int i = 0;
if ((iter = PyObject_GetIter(list)) == NULL) {
return -1;
}
while ((item = PyIter_Next(iter)) != NULL) {
if (PyLong_Check(item)) {
i++;
long long_item = PyLong_AsLong(item);
printf("%d long: %ld\n", i, long_item);
}
if PyFloat_Check(item) {
i++;
float float_item = PyFloat_AsDouble(item);
printf("%d float: %f\n", i, float_item);
}
if PyUnicode_Check(item) {
i++;
const char *unicode_item = PyUnicode_AsUTF8(item);
printf("%d unicode: %s\n", i, unicode_item);
}
Py_DECREF(item);
}
Py_DECREF(iter);
Py_DECREF(n1);
Py_DECREF(n2);
Py_DECREF(list);
if (Py_FinalizeEx() < 0) {
exit(120);
}
PyMem_RawFree(program);
return 0;
}