`PyTuple_Pack` segfault - PullRequest
       23

`PyTuple_Pack` segfault

0 голосов
/ 05 сентября 2018

У меня есть функция foo в модуле расширения Python, которая должна возвращать кортеж целых чисел в Python. Это можно легко сделать, используя Py_BuildValue:

static PyObject* 
foo(PyObject* self, PyObject* args)
{
    int a = 0;
    int b = 0;

    /* calculations and stuff */

    PyObject* out = Py_BuildValue("(iii)", a, b, a+b);
    Py_INCREF(out);

    return out;
}

Вместо Py_BuildValue я хочу использовать PyTuple_Pack, что гарантирует, что возвращаемое значение действительно является кортежем.

Документация Python C API говорит, что PyTuple_Pack(3, a, b, a+b) эквивалентно Py_BuildValue("(iii)", a, b, a+b). Обе функции возвращают новую ссылку типа PyPbject*.

Следовательно, учитывая приведенный выше код,

static PyObject* 
foo(PyObject* self, PyObject* args)
{
    /* ... */

    PyObject* out = PyTuple_Pack(3, a, b, a+b);
    Py_INCREF(out);

    return out;
}

должен сделать трюк, который не делает. Вместо этого я получаю сегфо. Что мне здесь не хватает?

1 Ответ

0 голосов
/ 05 сентября 2018

Разница:

  • Py_BuildValue("(ii)", a, b) ожидает, что a и b будут простыми значениями C-int.
  • PyTuple_Pack(2, a, b) ожидает, что a и b будут уже PyObject s (а не C-ints).

Документация гласит:

Значения кортежа инициализируются последующими аргументами n C, указывающими на объекты Python . PyTuple_Pack(2, a, b) эквивалентно Py_BuildValue("(OO)", a, b).

Чтобы использовать PyTuple_Pack, вам нужно сначала преобразовать int-значения в Python-Integer.

Проще использовать Py_BuildValue(). Если заключить в скобки строку формата в Py_BuildValue, результатом будет кортеж:

Py_BuildValue() не всегда создает кортеж. Он создает кортеж, только если его строка формата содержит две или более единиц формата. Если строка формата пуста, возвращается None; если он содержит ровно одну единицу формата, он возвращает любой объект, описанный этой единицей формата. Чтобы заставить его возвращать кортеж размером 0 или один, заключите в скобки строку формата .

Это означает, что вам не о чем беспокоиться, если вы создаете кортеж как минимум из двух элементов:

Py_BuildValue("ii", a, b)   # returns a tuple
Py_BuildValue("(ii)", a, b) # returns a tuple

Отличается, если есть только один элемент:

Py_BuildValue("i", a)    # returns an integer
# parenthesized:
Py_BuildValue("(i)", a)  # returns a tuple with an integer

или вообще без элементов:

Py_BuildValue("")    # returns None
# parenthesized:
Py_BuildValue("()")  # returns an empty tuple.

Так что просто убедитесь, что в строке формата есть круглые скобки, и возвращаемое значение будет кортежем.

...