从C返回对象到Python

11 投票
1 回答
2486 浏览
提问于 2025-04-16 18:36

我看过Python C-API的文档,也写过一些扩展模块。不过,我对从C函数返回Python对象的具体规则还是有点不太明白。

Python文档中的例子比较少,通常展示的是一个C函数返回Py_BuildValue的结果。这个Py_BuildValue会返回一个New Reference,并把这个引用的所有权转交给解释器。那么,我能否推断出一个一般规则:任何返回给Python的对象都必须是一个新引用,而从C函数返回对象就等于把这个对象的所有权转交给了解释器呢?

如果是这样,那如果返回的对象已经被其他东西拥有怎么办呢?比如,假设你写了一个C函数,它接收一个PyObject*,这个对象是一个tuple,然后你在它上面调用PyTuple_GetItem并返回结果。PyTuple_GetItem返回的是一个借用引用——这意味着这个项仍然是“由”元组拥有的。那么,返回像PyTuple_GetItem这样的结果的C函数在返回给解释器之前需要INCREF这个结果吗?

例如:

static PyObject* my_extension_module(PyObject* tup)
{
   PyObject* item = PyTuple_GetItem(tup, 1);
   if (!item) { /* handle error */ }

   return item; // <--- DO WE NEED TO INCREF BEFORE RETURNING HERE?
}

1 个回答

7

Python要求你暴露给它的任何函数都必须返回一个新的引用。如果你只有一个借用的引用,就需要调用Py_INCREF来创建一个新的引用。如果你返回的是一个借用的引用,Python会在用完这个引用后调用Py_DECREF,这可能会导致对象在仍然被使用的时候就被释放掉。

(这种“最终”释放在解释器退出时发生并不少见,这时候可能不会被注意到,但返回借用的引用仍然是个错误。)

撰写回答