如何检查 PyObject 是不是为列表?
Posted
技术标签:
【中文标题】如何检查 PyObject 是不是为列表?【英文标题】:How do I check if a PyObject is a list?如何检查 PyObject 是否为列表? 【发布时间】:2019-07-18 08:39:46 【问题描述】:我是 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 列表并返回所有元素的总和。如果我传递一个列表,该函数可以正常工作,如果我传递其他内容,但我会收到错误消息
SystemError: c:\_work\5\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
;
谢谢。
【问题讨论】:
使用boost::python
,它比纯 C - python 桥更容易掌握,除非你只使用 C。
【参考方案1】:
错误
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)
的简写,其中 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
类型以外的参数时。
【讨论】:
非常感谢,完美运行。但是我还是不明白,我的代码哪里出错了?在我的情况下,它不应该只返回零吗? @Klemens KasserollerSystemError: c:\_work\5\s\objects\listobject.c:187: bad argument to internal function
出现在 Py_ssize_t n = PyList_Size(o);
。如果您查看PyList_Size
实现,您可以看到它检查列表类型的对象是否调用PyErr_BadInternalCall
以上是关于如何检查 PyObject 是不是为列表?的主要内容,如果未能解决你的问题,请参考以下文章
Python C Api 将 PyObject * 传输到 c 数组中