问题描述
我已经搜索了一段时间,但即使问题很简单也找不到答案。 在 python 中,我声明了一个包含 N 个地方的列表,其元素是列表本身:
list_of_list = []
for i in range(N):
list_of_list.append([])
然后我想将此列表列表传递给我的 C 扩展并填充它/阅读它。例如,在 C:
void * fill_list_of_list (PyObject *args){
int ok;
PyObject *list_of_list;
int i,N;
ok = ( PyArg_ParseTuple(args,"iO",&N,&list_of_list));
for (i=0; i < N; i++){
/*would like to set,for each sublist,its first element to zero*/
PyList_SetItem( PyList_GetItem(list_of_list,i),PyFloat_FromDouble(0.) );
}
}
从python然后我想要以下代码:
print(list_of_list)
fill_list_of_list((N,list_of_list))
print(list_of_list)
输出(例如 N = 3):
[[],[],[]]
[[0.],[0.],[0.]]
但我收到了分段错误。
我做错了什么?请注意,问题确实出在列表列表上,因为以类似的方式我可以完美地处理浮动列表。与 numpy 浮点数数组和不同大小数组的 numpy 数组类似。
解决方法
PyList_SetItem 基本上替换列表中的一个项目,但您的列表是空的,所以没有任何东西可以替换。当您尝试这样做时,CPython API 应该设置一个异常。您可能想尝试改用 PyList_Append
。我还强烈建议您对 CPython 函数进行错误检查。
不过,我不确定这是否是唯一的问题,因为您需要提供一个最小的、可重现的示例(您的代码似乎有一些错误,例如 {{ 旁边的未配对 (
1}} 和未声明的变量 PyArg_ParseTuple
)。我也不熟悉使用 SWIG,因此请将此视为部分答案,因为我可能错过了更具体的 SWIG 内容。
编辑
根据评论,这是一个使用 timestamps
的工作示例。请注意,我只使用 CPython API(没有 SWIG)。如果您想自己构建和运行此示例,还必须编辑 Python 模块文件的路径。
PyList_Append
/* main.cpp */
#include <iostream>
#include <cstdio>
#define PY_SSIZE_T_CLEAN
#include <Python.h>
#define PYTHONFILE "Path\\To\\Python\\File\\test.py" // <-- Change this to the location
// of your Python module file
extern "C" {
static PyObject *Foo_fillListOfLists(PyObject *,PyObject *);
}
static PyMethodDef FooMethods[] =
{
{
"fill_list_of_lists",Foo_fillListOfLists,METH_VARARGS,"Fills list of lists with zeros."
},{ NULL,NULL,NULL }
};
static struct PyModuleDef FooModule =
{
PyModuleDef_HEAD_INIT,"foo",-1,FooMethods
};
PyMODINIT_FUNC PyInit_Foo(void)
{
return PyModule_Create(&FooModule);
}
void RunPython()
{
FILE *fp = NULL;
if (fopen_s(&fp,PYTHONFILE,"rb"))
return;
if (PyImport_AppendInittab("foo",PyInit_Foo) == -1) {
std::cout << "ERROR: Could not extend built-in modules table\n";
fclose(fp);
return;
}
Py_Initialize();
PyRun_SimpleFile(fp,PYTHONFILE);
Py_FinalizeEx();
fclose(fp);
}
int main(int argc,char *argv[])
{
RunPython();
return 0;
}
PyObject *Foo_fillListOfLists(PyObject *self,PyObject *args)
{
PyObject *listOfLists;
Py_ssize_t listLen;
if (!PyArg_ParseTuple(args,"O",&listOfLists))
return NULL;
if (!PyList_CheckExact(listOfLists)) {
PyErr_SetString(PyExc_RuntimeError,"Received non-list type object.");
return NULL;
}
listLen = PyList_GET_SIZE(listOfLists);
for (Py_ssize_t i = 0; i < listLen; ++i) {
PyObject *listInList = PyList_GET_ITEM(listOfLists,i);
if (!PyList_CheckExact(listInList)) {
PyErr_SetString(PyExc_RuntimeError,"Non-list type found in list of lists.");
return NULL;
}
// This is what you need to fix your error.
if (PyList_Append(listInList,PyFloat_FromDouble(0)))
return NULL;
}
return Py_None;
}
输出:
# test.py
import foo
list_of_lists = []
for i in range(3):
list_of_lists.append([])
print(list_of_lists)
foo.fill_list_of_lists(list_of_lists)
print(list_of_lists)