`PyTuple_Pack` 段错误

Max*_*ers 4 python cpython python-3.x python-extensions

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;
}
Run Code Online (Sandbox Code Playgroud)

而不是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;
}
Run Code Online (Sandbox Code Playgroud)

应该可以解决问题,但事实并非如此。相反,我得到了一个段错误。我在这里缺少什么?

ead*_*ead 5

区别在于:

  • Py_BuildValue("(ii)", a, b)期望a并且b是简单的 C-int 值。
  • PyTuple_Pack(2, a, b)期望a并且 b已经PyObject是 s(而不是 C-int)。

文件说:

元组值被初始化为指向Python 对象的后续 n 个 C 参数。PyTuple_Pack(2, a, b)相当于Py_BuildValue("(OO)", a, b)

为了使用,PyTuple_Pack您需要先将整数值转换为 Python 整数。

使用起来更简单Py_BuildValue()。如果将格式字符串括在 中Py_BuildValue,结果将是一个元组:

Py_BuildValue()并不总是构建一个元组。仅当其格式字符串包含两个或多个格式单元时,它才会构建元组。如果格式字符串为空,则返回 None;如果它只包含一个格式单元,则返回该格式单元所描述的任何对象。要强制它返回大小为 0 或 1 的元组,请将格式 string 括起来

这意味着:如果您从至少两个元素构造一个元组,则无需担心:

Py_BuildValue("ii", a, b)   # returns a tuple
Py_BuildValue("(ii)", a, b) # returns a tuple
Run Code Online (Sandbox Code Playgroud)

如果只有一个元素,则不同:

Py_BuildValue("i", a)    # returns an integer
# parenthesized:
Py_BuildValue("(i)", a)  # returns a tuple with an integer
Run Code Online (Sandbox Code Playgroud)

或根本没有元素:

Py_BuildValue("")    # returns None
# parenthesized:
Py_BuildValue("()")  # returns an empty tuple.
Run Code Online (Sandbox Code Playgroud)

所以只要确保格式字符串中有括号,返回的值将是一个元组。