使用Python3/capi更新数组元素

使用Python3/capi更新数组元素,python,python-c-api,Python,Python C Api,我有一个模块方法,它接收python列表,然后输出相同的列表,所有项乘以100 我试着尽可能接近,但仍然遇到问题 static PyObject * test_update_list(PyObject *self, PyObject *args) { PyObject *listObj = NULL; PyObject *item = NULL; PyObject *mult = PyLong_FromLong(100); PyObject *incremente

我有一个模块方法,它接收python列表,然后输出相同的列表,所有项乘以100

我试着尽可能接近,但仍然遇到问题

static PyObject *
test_update_list(PyObject *self, PyObject *args)
{
    PyObject *listObj = NULL;
    PyObject *item = NULL;
    PyObject *mult = PyLong_FromLong(100);
    PyObject *incremented_item = NULL;

    if (!PyArg_ParseTuple(args, "O", &listObj))
    {
        return NULL;
    }

    /* get the number of lines passed to us */
    Py_ssize_t numLines = PyList_Size(listObj);

    /* should raise an error here. */
    if (numLines < 0) return NULL; /* Not a list */

    for (Py_ssize_t i=0; i<numLines; i++) {
        // pick the item 
        item = PyList_GetItem(listObj, i);

        if (mult == NULL)
            goto error;

        // increment it
        incremented_item = PyNumber_Add(item, mult);

        if (incremented_item == NULL)
            goto error;

        // update the list item
        if (PyObject_SetItem(listObj, i, incremented_item) < 0)
            goto error;

    }
error:
    Py_XDECREF(item);
    Py_XDECREF(mult);
    Py_XDECREF(incremented_item);
    return listObj;
};
静态PyObject*
测试更新列表(PyObject*self,PyObject*args)
{
PyObject*listObj=NULL;
PyObject*item=NULL;
PyObject*mult=PyLong_FromLong(100);
PyObject*递增的_项=NULL;
if(!PyArg_ParseTuple(args,“O”&listObj))
{
返回NULL;
}
/*获取传递给我们的行数*/
Py_ssize_t numLines=PyList_尺寸(listObj);
/*应该在这里引发一个错误*/
if(numLines<0)返回NULL;/*不是列表*/
对于(Py_ssize_t i=0;i 1测试添加测试更新列表([1,2,3])
SystemError:返回了一个带有错误集的结果

非常感谢您的帮助。

因此,您有许多问题都需要纠正。我将这些问题都列在单独的标题下,以便您一次只看一个问题

始终返回
listObj
当for循环中出现错误时,您将转到仍在返回列表的错误标签。

返回时不增加
listObj
ref计数 调用函数时,会向您提供对参数的借用引用。当您返回其中一个参数时,您正在创建对列表的新引用,因此必须增加其引用计数。否则,解释器的引用计数将比对象的实际引用数低一个。这将最终会出现一个错误,即解释器在只有1个引用而不是0的情况下取消分配列表!这可能会导致seg故障,或者在最坏的情况下,可能会导致程序访问的随机部分被取消分配并分配给其他对象

PyObject\u SetItem
与基元一起使用 可以与dicts和其他实现
obj[key]=val
的类一起使用。因此,您不能为它提供类型为
Py_-ssize\t
的参数。相反,使用它只能接受
Py_-ssize\t
作为其索引参数

递增项
PyObject\u SetItem
PyList\u SetItem
都处理减少已在设置位置的对象的引用计数。因此,我们不必担心管理
项的引用计数,因为我们只处理从列表借用的引用。这对函数窃取对
递增的\u项的引用
,因此我们也不需要担心管理其引用计数

错误参数的内存泄漏 例如,当您使用int调用函数时。您将创建一个对100 int对象的新引用,但由于
返回NULL
而不是
转到error
,此引用将丢失。因此,您需要以不同的方式处理此类情况。在我的解决方案中,我将
PyLong_从long
调用移动到a之后rg和类型检查。这样,我们只有在保证使用这个新的*对象后才能创建它

工作代码 旁注:我删除了goto语句,因为只剩下一条了,所以在那一点上进行错误处理比以后更合理

静态PyObject*
测试添加更新列表(PyObject*self,PyObject*args)
{
PyObject*listObj=NULL;
PyObject*item=NULL;
PyObject*mult=NULL;
PyObject*递增的_项=NULL;
Py_-ssize_-t numLines;
if(!PyArg_ParseTuple(args,“O:update_list”、&listObj))
{
返回NULL;
}
如果(!PyList_Check(listObj)){
PyErr_badargum();
返回NULL;
}
/*获取传递给我们的行数*/
//我不想依赖这个函数的错误检查,因为它会给出一个奇怪的堆栈跟踪。
//相反,我们使用Py_ListCheck()和Pyrr_BadArgument(),如上所述
//现在列表,然后派利斯特_大小将永远不会抛出错误,因此我们可以使用
//PyList_GET_SIZE(列表对象j)。
numLines=PyList_尺寸(listObj);
//仅在此处初始化mult,否则上述返回将导致内存泄漏
mult=PyLong_FromLong(100);
if(mult==NULL){
返回NULL;
}

对于(Py_ssize_t i=0;i您是如何编译此文件的?编译器应该发出各种警告。其中最重要的是,您正在向
PyObject_SetItem
而不是python int对象传递一个基本C int。也许您打算使用
PyList_SetItem
PyList_Size
设置一个错误;您没有到。每个错误都必须返回
NULL
。创建时只检查一次
mult
PyNumber\u Add
不会相乘。另外,声明变量更接近其(实数)初始化,所以你不觉得需要给它们无意义的初始值。非常清楚我错在哪里。干杯。为了回答你最初的问题,我使用
python setup.py build
编译。我得到的一个警告确实是关于将C int传递给
PyObject\u SetItem
。实际上是整数值b介于-5和256之间的数据在整数池中
---------------------------------------------------------------------------
SystemError                               Traceback (most recent call last)
SystemError: null argument to internal routine

The above exception was the direct cause of the following exception:

SystemError                               Traceback (most recent call last)
<ipython-input-3-da275aa3369f> in <module>()
----> 1 testadd.test_update_list([1,2,3])

SystemError: <built-in function ulist> returned a result with an error set