如何检查PyObject是否为列表?

时间:2019-07-18 08:39:46

标签: python c++ python-c-api

我是Python / C API的新手,虽然我有一些基本功能可以使用,但我正在为这一功能而苦苦挣扎。

make rx production debug

基本上,这是文档页面上的简介中的功能。它应该接收一个python列表并返回所有元素的总和。如果我传递了一个列表,如果我传递了其他内容,则该功能运行正常,但是我收到了错误消息

PyObject* sum_elements(PyObject*, PyObject *o) 
{
    Py_ssize_t n = PyList_Size(o);
    long total = 0;
    if (n < 0)
    {
        return PyLong_FromLong(total);
    }
    PyObject* item;
    for (int i = 0; i < n; i++) 
    {
        item = PyList_GetItem(o, i);
        if (!PyLong_Check(item)) continue;
        total += PyLong_AsLong(item);
    }
    return PyLong_FromLong(total);
}

这种情况应由SystemError: c:\_work\5\s\objects\listobject.c:187: bad argument to internal function 语句处理,因为如果传递的对象不是列表,则n为-1。

我通过以下方式绑定函数:

if (n<0)

谢谢。

1 个答案:

答案 0 :(得分:4)

错误

SystemError: c:\_work\5\s\objects\listobject.c:187: bad argument to internal function

实际发生在

Py_ssize_t n = PyList_Size(o)

因为PyList_Size进行了额外的检查以查看列表类型的对象是否存在,否则将调用PyErr_BadInternalCall API来引发SystemError。请参见listobject.c

PyList_Size的实现
PyList_Size(PyObject *op)
{
    if (!PyList_Check(op)) {
        PyErr_BadInternalCall();
        return -1;
    }
    else
        return Py_SIZE(op);
}

PyErr_BadInternalCall的缩写,PyErr_SetString(PyExc_SystemError, message),其中消息指示内部操作(例如Python / C API函数)被非法参数调用。

您应该使用PyList_Check API来检查对象是否为list类型。根据文档,如果对象是列表对象或列表类型的子类型的实例,则返回true。

PyObject* sum_elements(PyObject*, PyObject *o) 
{    
    // Check if `o` is of `list` type, if not raise `TypeError`.
    if (!PyList_Check(o)) {
         PyErr_Format(PyExc_TypeError, "The argument must be of list or subtype of list");
         return NULL;
    }
    // The argument is list type, perform the remaining calculations.
    Py_ssize_t n = PyList_Size(o);
    long total = 0;
    if (n < 0)
    {
        return PyLong_FromLong(total);
    }
    PyObject* item;
    for (int i = 0; i < n; i++) 
    {
        item = PyList_GetItem(o, i);
        if (!PyLong_Check(item)) continue;
        total += PyLong_AsLong(item);
    }
    return PyLong_FromLong(total);
}

一旦添加了此额外检查,函数调用就会提高

TypeError: The argument must be of list or sub type of list

提供了list类型以外的参数时。