如何检查 PyObject 是否为列表?
How do I check if a PyObject is a list?
我是 Python/C API 的新手,虽然我有一些基本功能可以使用,但我在这个功能上遇到了困难。
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);
}
基本上这是文档页面上介绍的功能。它应该收到一个 python 列表和 return 所有元素的总和。如果我传递一个列表,该函数工作正常,如果我传递其他东西,但是我收到错误消息
SystemError: c:\_work\s\objects\listobject.c:187: bad argument to internal function
这种情况应该由if (n<0)
语句处理,因为如果传递的对象不是列表,则n 为-1。
我通过以下方式绑定函数:
static PyMethodDef example_module_methods[] = {
{ "sum_list", (PyCFunction)sum_elements, METH_O, nullptr},
{ nullptr, nullptr, 0, nullptr }
};
谢谢。
错误
SystemError: c:\_work\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);
}
The PyErr_BadInternalCall a shorthand for PyErr_SetString(PyExc_SystemError, message)
,其中消息表示内部操作(例如 Python/C API 函数)被调用非法参数。
您应该使用 PyList_Check
API 来检查对象是否为 list
类型。根据文档,如果对象是列表对象或列表类型的子类型的实例,则 Return 为真。
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
类型时。
我是 Python/C API 的新手,虽然我有一些基本功能可以使用,但我在这个功能上遇到了困难。
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);
}
基本上这是文档页面上介绍的功能。它应该收到一个 python 列表和 return 所有元素的总和。如果我传递一个列表,该函数工作正常,如果我传递其他东西,但是我收到错误消息
SystemError: c:\_work\s\objects\listobject.c:187: bad argument to internal function
这种情况应该由if (n<0)
语句处理,因为如果传递的对象不是列表,则n 为-1。
我通过以下方式绑定函数:
static PyMethodDef example_module_methods[] = {
{ "sum_list", (PyCFunction)sum_elements, METH_O, nullptr},
{ nullptr, nullptr, 0, nullptr }
};
谢谢。
错误
SystemError: c:\_work\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);
}
The PyErr_BadInternalCall a shorthand for PyErr_SetString(PyExc_SystemError, message)
,其中消息表示内部操作(例如 Python/C API 函数)被调用非法参数。
您应该使用 PyList_Check
API 来检查对象是否为 list
类型。根据文档,如果对象是列表对象或列表类型的子类型的实例,则 Return 为真。
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
类型时。