首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >为什么PySequence_GetItem会返回一个新的引用?

为什么PySequence_GetItem会返回一个新的引用?
EN

Stack Overflow用户
提问于 2019-09-04 15:41:41
回答 1查看 390关注 0票数 1

我在一个C/C++ python扩展中发现了一个内存泄漏,因为我假设PySequence_GetItem会像PyList_GetItemPyTuple_GetItem一样返回一个借用的引用。我的问题是:为什么PySequence_GetItem返回新引用,而PyList_GetItemPyTuple_GetItem返回借用的引用?

docs

代码语言:javascript
运行
复制
PyObject* PySequence_GetItem(PyObject *o, Py_ssize_t i)
    Return value: New reference.
    Return the ith element of o, or NULL on failure. This is the equivalent of the Python expression o[i].
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-09-04 23:57:31

您可以从PySequence获得新的引用,因为这是PySequence-protocol定义的。

然而,以这种方式定义协议有很好的理由:并不是所有的序列都是由内存支持的(如listtuple),对于某些项是动态创建的(如rangeunicode)。

对于listtuple,所有的项目都归list/tuple所有(它们不是临时对象),所以我们可以借用它们(借用是一个小优化)-- list/tuple最终会释放内存。

range是序列的另一个示例。它实现了PySequence-protocol):

代码语言:javascript
运行
复制
static PySequenceMethods range_as_sequence = {
    (lenfunc)range_length,      /* sq_length */
    0,                          /* sq_concat */
    0,                          /* sq_repeat */
    (ssizeargfunc)range_item,   /* sq_item */
    0,                          /* sq_slice */
    0,                          /* sq_ass_item */
    0,                          /* sq_ass_slice */
    (objobjproc)range_contains, /* sq_contains */
};

但是,PySequence_GetItem返回的对象是临时的(即没有人拥有函数外部对它的引用),我们可以在range_item的源代码中验证这一点

代码语言:javascript
运行
复制
static PyObject *
range_item(rangeobject *r, Py_ssize_t i)
{
    PyObject *res, *arg = PyLong_FromSsize_t(i);
    if (!arg) {
        return NULL;
    }
    res = compute_range_item(r, arg);
    Py_DECREF(arg);
    return res;
}

其中,compute_range_item归结为compute_item

代码语言:javascript
运行
复制
static PyObject *
compute_item(rangeobject *r, PyObject *i)
{
    PyObject *incr, *result;
    /* PyLong equivalent to:
     *    return r->start + (i * r->step)
     */
    incr = PyNumber_Multiply(i, r->step);
    if (!incr)
        return NULL;
    result = PyNumber_Add(r->start, incr);
    Py_DECREF(incr);
    return result;
}

没有人拥有返回的result中的对象,因此接收方必须注意减少引用计数。

也许还有其他可能的解决方案(创建项的某种缓存),但返回一个新的引用是处理动态创建项问题的最简单/透明的方法。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/57783652

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档