用C扩展python:将列表传递给PyArg_ParseTuple

用C扩展python:将列表传递给PyArg_ParseTuple,python,c,python-c-api,python-c-extension,Python,C,Python C Api,Python C Extension,我一直在尝试用C来扩展python,到目前为止,基于,我已经在编写小型C函数和用python扩展方面取得了相当的成功 然而,我现在突然想到一个相当简单的问题——我无法找到解决办法。所以,我想做的是将一个双列表传递给我的C函数。例如,要传递一个int,我执行以下操作: int squared(int n) { if (n > 0) return n*n; else return 0; } static PyObject* squaredfun

我一直在尝试用C来扩展python,到目前为止,基于,我已经在编写小型C函数和用python扩展方面取得了相当的成功

然而,我现在突然想到一个相当简单的问题——我无法找到解决办法。所以,我想做的是将一个
双列表
传递给我的C函数。例如,要传递一个
int
,我执行以下操作:

int squared(int n)
{
    if (n > 0)
        return n*n;
    else
        return 0;
}

static PyObject*
squaredfunc(PyObject* self, PyObject* args)
{
    int n;

    if (!PyArg_ParseTuple(args, "i", &n))
        return NULL;

    return Py_BuildValue("i", squared(n));
}
这会将
int
n
毫无问题地传递给名为
squared
的C函数

但是,如何将
列表
传递给C函数呢?我确实试着用谷歌搜索并阅读了文档,到目前为止,我还没有找到任何有用的东西

如果有人能给我指出正确的方向,我将不胜感激

谢谢。

只能处理简单的C类型、复数、
char*
PyStringObject*
PyUnicodeObject*
PyObject*
。处理PyListObject的唯一方法是使用“O”的某些变体并将该对象提取为PyObject*。然后可以使用检查对象是否确实是列表(
PyList\u check
)。然后,您可以使用
PyList\u Size
PyList\u GetItem
在列表上迭代。请注意,在迭代时,您将获得
PyObject*
,并且必须使用来访问实际值(通过执行
PyFloat\u检查
PyFloat\u AsDouble
),作为列表API的替代,您可以更灵活地使用(在这种情况下,您应该只使用PyIter\u检查)。这将允许您迭代任何支持迭代器协议的内容,如列表、元组、集合等

最后,如果您确实希望函数接受
双n[]
并且希望避免所有手动转换,那么您应该使用类似的方法。学习曲线和API更加复杂,但是boost::python将自动为您处理所有转换

下面是一个使用迭代器协议的循环示例(这未经测试,您需要填写错误处理代码):

该函数允许您使用格式字符串
“O!”
直接强制转换到Python对象子类型(请注意,这与普通的
“O”
不同)。如果参数与指定的PyObject类型不匹配,它将抛出TypeError。例如:

PyObject *pList;
PyObject *pItem;
Py_ssize_t n;
int i;

if (!PyArg_ParseTuple(args, "O!", &PyList_Type, &pList)) {
    PyErr_SetString(PyExc_TypeError, "parameter must be a list.");
    return NULL;
}

n = PyList_Size(pList);
for (i=0; i<n; i++) {
    pItem = PyList_GetItem(pList, i);
    if(!PyInt_Check(pItem)) {
        PyErr_SetString(PyExc_TypeError, "list items must be integers.");
        return NULL;
    }
}
PyObject*pList;
PyObject*pItem;
Py_ssize_t n;
int i;
if(!PyArg_ParseTuple(args,“O!”,&PyList_Type,&pList)){
PyErr_SetString(PyExc_TypeError,“参数必须是列表”);
返回NULL;
}
n=PyList_尺寸(pList);

对于(i=0;我想你需要
“O”
而不是
“i”
来表示你接受了一个任意对象。@mgilson:谢谢。但是,我该如何更改我的
int n
声明来反映这一点呢?我应该只做
双n[]
?不,它可能是一个
PyObject*lst;
,或者我认为类似的东西。@mgilson:我想知道是否有这样一个例子,我可以看看并试着理解?再次感谢。不确定。我知道的不多,我知道的是从阅读您已经链接的python源代码/文档中了解的。有什么办法吗要禁止PyArg_ParseTuple引发异常?我想要一个可以接受多种类型的函数。@Tony:PyArg_ParseTuple(args,“O!”,&PyList_Type,&pList)中的
“O!”,&PyList_Type
格式字符串的要点
是让它检查类型并抛出TypeError。如果你不想让它检查类型,那么就用
PyArg\u语法元组(args,“O”和&pList)
(顺便说一句,
&PyList\u type
中的
&
非常重要!第一次就咬到我了。)@Tony:或者,如果“一个可以接受多种类型的函数”你的意思是“一个某些参数是可选的函数”,这是由处理的。如果你在这方面还有问题,我建议你单独提问。
PyObject *pList;
PyObject *pItem;
Py_ssize_t n;
int i;

if (!PyArg_ParseTuple(args, "O!", &PyList_Type, &pList)) {
    PyErr_SetString(PyExc_TypeError, "parameter must be a list.");
    return NULL;
}

n = PyList_Size(pList);
for (i=0; i<n; i++) {
    pItem = PyList_GetItem(pList, i);
    if(!PyInt_Check(pItem)) {
        PyErr_SetString(PyExc_TypeError, "list items must be integers.");
        return NULL;
    }
}