Python C扩展:PyList的Py_DECREF

时间:2018-01-27 01:27:35

标签: python c swig

我有一个关于如何在C中正确使用Py_DECREF()的问题。所以假设我有一个名为build_list()的函数,它接受一个字符串链表作为其输入参数并返回一个Python列表如果一切顺利,或NULL如果有错误。

以下是简约的例子:

struct strlist {
    char *str;
    size_t len;
    struct strlist *next;
};

PyObject *build_list (struct strlist *inlist) {
    struct strlist *node = NULL;
    PyObject *tmp_obj = NULL;
    int success;

    PyObject *ret_obj = PyList_New(0);
    if (ret_obj == NULL) {
        return NULL;
    }

    node = inlist;
    while (node != NULL) {
        tmp_obj = PyString_FromStringAndSize(node->str, node->len);
        if (tmp_obj == NULL) {
            Py_DECREF(ret_obj);
            return NULL;
        }
        else {
            success = PyList_Append(ret_obj, tmp_obj);
            Py_DECREF(tmp_obj);
            if (success != 0) {
                Py_DECREF(ret_obj);
                return NULL;
            }
        }
        node = node->next;
    }
    return ret_obj;
}

在这种情况下,我是否正确使用了Py_DECREF()

我的具体问题是: 如果在发生错误之前已将一些元素附加到列表中,我的代码将直接递减对列表的引用(在success != 0内),而列表中的元素在技术上仍然具有引用计数为1.我是否应该减少在我最终减少对列表的引用之前,每个元素的引用都是第一个?

谢谢。

1 个答案:

答案 0 :(得分:1)

创建list后,它的引用数为1.每个string生成一个引用计数为1,并将其附加到列表中将其增加到2(因为list并且您的函数引用它)。因此DECREF之后的Append()正确,因为您的函数不再使用string本身。 在两个错误路径(tmp_obj == NULLsuccess != 0)内,DECREF - list对象将释放该对象(因为它的引用现在为0)。 list - 对象将遍历它的每个成员和DECREF,将每个string的引用数量减少为0,从而释放它们。

长话短说:您的代码是正确的。列表中的元素必须具有(至少)1的引用计数,因为列表引用它们。它是list DECREF成员的exit()专属责任。

作为练习,你可以尝试减少字符串'记得自己。解释器很可能会崩溃(可能在{{1}}),因为当列表被释放时,字符串' refcounts转到-1,触发断言。