Расширяя Python с помощью C, Как динамически построить сложную структуру в C? - PullRequest
0 голосов
/ 05 мая 2019

Я хотел бы создать функцию C, которая возвращает список кортежей, список диктов или, что еще лучше, список объектов класса, который я определил в другом модуле python.

В документации по C API («API Python / C») упоминается, что для построения сложного объекта мне нужно вызвать Py_BuildValue, который использует переменное число параметров, или Py_VaBuildValue, который использует va_list аргумент.

Поскольку C не может динамически выполнять вызов с переменным числом аргументов, я не могу использовать Py_BuildValue и должен использовать Py_VaBuildValue, но в поисках того, как построить переменную va_list, я нахожу ответы, которые Там нет возможности заполнить va_list явно , а говорит мне сделать его из функции переменных параметров , которая отрицает цель ... и из сделанных тестов все, что я получаю, это ошибки сегментации и основные отвалы.

Итак, как мне использовать эти функции?

1 Ответ

1 голос
/ 05 мая 2019

Вы не должны использовать эти функции для построения структур данных динамического размера. В FAQ говорится, что PyTuple_Pack следует использовать вместо Py_BuildValue для кортежа произвольного размера, но это тоже неправильно; Я не знаю, почему это так говорит. PyTuple_Pack имеет те же проблемы с varargs, что и Py_BuildValue.

Чтобы построить кортеж переменной длины из C, используйте PyTuple_New, чтобы создать неинициализированный кортеж желаемой длины, затем зациклите индексы и установите элементы с помощью PyTuple_SET_ITEM. Да, это мутирует кортеж. PyTuple_SET_ITEM является только безопасным для использования для инициализации свежих кортежей, которые еще не подвергались воздействию другого кода. Также имейте в виду, что PyTuple_SET_ITEM крадет ссылку на новый элемент.

Например, чтобы построить кортеж из целых чисел от 0 до n-1:

PyObject *tup = PyTuple_New(n);
for (int i = 0; i < n; i++) {
    // Note that PyTuple_SET_ITEM steals the reference we get from PyLong_FromLong.
    PyTuple_SET_ITEM(tup, i, PyLong_FromLong(i));
}

Чтобы создать список переменной длины из C, вы можете сделать то же самое с помощью PyList_New и PyList_SET_ITEM, или вы можете создать пустой список с помощью PyList_New(0) и добавлять элементы с помощью PyList_Append, так же, как вы будет использовать [] и append в Python, если у вас нет списочного понимания или умножения последовательности.

...