Python/C API - 结果不显示
Python/C API - The result is not displayed
我想在 Python 中集成 C 模块,所以我的选择落在了接口 Python.h
上。所有编译都没有错误和警告,所以我不明白问题是什么。
C方:
#include <python3.5m/Python.h>
...
#define PyInt_AsLong(x) (PyLong_AsLong((x)))
typedef PyObject* Py;
static Py getSumma(Py self, Py args){
Py nums;
if (!PyArg_ParseTuple(args, "O", &nums)){
return NULL;
}
size_t numsAmount = PyList_Size(args);
int32_t summa = 0;
for (size_t i = 0; i < numsAmount; i++){
Py temp = PyList_GetItem(nums, i);
int32_t num = PyInt_AsLong(temp);
summa += num;
}
return Py_BuildValue("l", summa);
}
static PyMethodDef moduleMethods[] = {
{"getSumma", (PyCFunction)getSumma, METH_VARARGS, NULL},
{NULL, NULL, 0, NULL}
};
static PyModuleDef SummaLogic = {
PyModuleDef_HEAD_INIT,
"SummaLogic",
"",
-1,
moduleMethods
};
PyMODINIT_FUNC PyInit_SummaLogic(void){
return PyModule_Create(&SummaLogic);
}
setup.py:
from distutils.core import setup, Extension
SummaLogic = Extension("SummaLogic", sources=['SummaLogic.c'])
setup(ext_modules=[SummaLogic])
Python 方:
from SummaLogic import getSumma
if __name__ == "__main__":
a = [1, 2, 3]
b = getSumma(a)
print(b)
这似乎是正确的,但是当我在终端中启动它时 - 没有任何反应,只是没有任何 activity 挂起。我能错过什么?
它归结为 PyList_Size
并且您不检查那里的错误。
您可能想在 nums
上使用它,而不是 args
作为参数。然而你在 args
上使用了一件非常有趣的事情:
args
是 tuple
,
- 因此
PyList_Size
失败并 returned -1
- 被转换为无符号
size_t
的 -1
可能会产生一个非常大的数字,可能 2**64-1
- 因此您的迭代运行 "very long time" 因为迭代
2**64-1
项目需要相当长的时间(除了所有越界内存访问)。
快速解决方法是使用:
Py_ssize_t listlength = PyList_Size(nums); /* nums instead of args */
if (listlength == -1) { /* check for errors */
return NULL;
}
size_t numsAmount = (size_t)listlength /* cast to size_t only after you checked for errors */
但是你应该检查错误条件是什么,并在每次 python C API 函数调用后测试它们,否则你会得到很多未定义的行为。另外我可能会坚持使用定义的 return 类型而不是 int32_t
(PyInt_AsLong
returns long
所以你也可能会在那里遇到奇怪的转换错误!) , size_t
, ... 和 typedef PyObject* Py;
让经常编写 C 扩展的人变得非常棘手。
我想在 Python 中集成 C 模块,所以我的选择落在了接口 Python.h
上。所有编译都没有错误和警告,所以我不明白问题是什么。
C方:
#include <python3.5m/Python.h>
...
#define PyInt_AsLong(x) (PyLong_AsLong((x)))
typedef PyObject* Py;
static Py getSumma(Py self, Py args){
Py nums;
if (!PyArg_ParseTuple(args, "O", &nums)){
return NULL;
}
size_t numsAmount = PyList_Size(args);
int32_t summa = 0;
for (size_t i = 0; i < numsAmount; i++){
Py temp = PyList_GetItem(nums, i);
int32_t num = PyInt_AsLong(temp);
summa += num;
}
return Py_BuildValue("l", summa);
}
static PyMethodDef moduleMethods[] = {
{"getSumma", (PyCFunction)getSumma, METH_VARARGS, NULL},
{NULL, NULL, 0, NULL}
};
static PyModuleDef SummaLogic = {
PyModuleDef_HEAD_INIT,
"SummaLogic",
"",
-1,
moduleMethods
};
PyMODINIT_FUNC PyInit_SummaLogic(void){
return PyModule_Create(&SummaLogic);
}
setup.py:
from distutils.core import setup, Extension
SummaLogic = Extension("SummaLogic", sources=['SummaLogic.c'])
setup(ext_modules=[SummaLogic])
Python 方:
from SummaLogic import getSumma
if __name__ == "__main__":
a = [1, 2, 3]
b = getSumma(a)
print(b)
这似乎是正确的,但是当我在终端中启动它时 - 没有任何反应,只是没有任何 activity 挂起。我能错过什么?
它归结为 PyList_Size
并且您不检查那里的错误。
您可能想在 nums
上使用它,而不是 args
作为参数。然而你在 args
上使用了一件非常有趣的事情:
args
是tuple
,- 因此
PyList_Size
失败并 returned-1
- 被转换为无符号
size_t
的-1
可能会产生一个非常大的数字,可能2**64-1
- 因此您的迭代运行 "very long time" 因为迭代
2**64-1
项目需要相当长的时间(除了所有越界内存访问)。
快速解决方法是使用:
Py_ssize_t listlength = PyList_Size(nums); /* nums instead of args */
if (listlength == -1) { /* check for errors */
return NULL;
}
size_t numsAmount = (size_t)listlength /* cast to size_t only after you checked for errors */
但是你应该检查错误条件是什么,并在每次 python C API 函数调用后测试它们,否则你会得到很多未定义的行为。另外我可能会坚持使用定义的 return 类型而不是 int32_t
(PyInt_AsLong
returns long
所以你也可能会在那里遇到奇怪的转换错误!) , size_t
, ... 和 typedef PyObject* Py;
让经常编写 C 扩展的人变得非常棘手。