从 C 返回对象到 Python
我阅读了 Python C-API 的文档,甚至编写了一些扩展模块。然而,当涉及到从 C 函数返回 Python 对象时,我仍然有点不清楚确切的语义。
Python 文档中的有限示例通常显示返回 Py_BuildValue
结果的 C 函数。现在,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?
}
I've read the documentation for the Python C-API, and even written a few extension modules. However, I'm still a bit unclear on the exact semantics when it comes to returning Python objects from a C function.
The limited examples in the Python docs usually show a C function which returns the result of Py_BuildValue
. Now, Py_BuildValue
returns a New Reference
, and transfers ownership of this reference over to the interpreter. So, can I extrapolate from this that it is a general rule that any object returned to Python must be a new reference, and that returning an object from a C function is the same as transferring ownership of the object over to the interpreter?
If so, what about cases where you return an object that is already owned by something? For example, suppose you write a C function which takes in a PyObject*
which is a tuple
, and you call PyTuple_GetItem
on it and return the result. PyTuple_GetItem
returns a borrowed reference - meaning that the item is still "owned" by the tuple. So, does a C function which returns the result of something like PyTuple_GetItem
have to INCREF
the result before returning it to the interpreter?
For example:
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?
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
Python 期望您暴露给它的任何函数都返回一个新引用,是的。如果您只有借用的引用,则必须调用
Py_INCREF
来提供新的引用。如果您返回借用的引用,Python 将继续调用 Py_DECREF(当引用完成时),最终将导致对象在仍在使用时被释放。(在解释器退出期间发生“最终”释放的情况并不罕见,在这种情况下,它可能会被忽视,但返回借用的引用仍然是一个错误。)
Python expects any function you expose to it to return a new reference, yes. If you only have a borrowed reference, you have to call
Py_INCREF
to give a new reference. If you return a borrowed reference, Python will proceed to callPy_DECREF
(when it's done with the reference), and eventually that will cause the object to be freed while it is still in use.(It's not uncommon for that "eventual" freeing to happen during interpreter exit, in which case it may go unnoticed, but it's still a mistake to return borrowed references.)