我尝试编写一个Numpy扩展模块。问题是我不确定如何正确将指向PyArrayObject
的指针传递给C函数,这将导致以下行为。考虑下面的代码:
/* File: test_mod.c */
#define NPY_NO_DEPRECATED_API NPY_1_8_API_VERSION
#define PY_ARRAY_UNIQUE_SYMBOL __NP_ARRAY_API
#include <Python.h>
#include <numpy/arrayobject.h>
#include "test_utilities.h"
static PyObject *
test_mod(PyObject* self, PyObject* args) {
PyArrayObject* arr;
if(!PyArg_ParseTuple(args, "O")) {
printf("Error while parsing objects");
return NULL;
}
/* do some checks
... */
do_something(&arr);
return Py_None;
}
/* Method table
... */
/* Module definition structure
... */
/* Module init function
... */
我想通过引用C函数来传递arr
。在上面的片段中,arr
是PyArrayObject
的劣势,后者是C struct
。因此,我想出了以下定义:
/* File: test_utilities.c */
#define NPY_NO_DEPRECATED_API NPY_1_8_API_VERSION
#define NO_IMPORT_ARRAY
#define PY_ARRAY_UNIQUE_SYMBOL __NP_ARRAY_API
#include <numpy/arrayobject.h>
void
do_something(struct PyArrayObject **arr) {
int d = PyArray_NDIM(*arr));
npy_intp N = PyArray_SIZE(*arr);
printf("%i, %li", d, N);
}
PyArray_NDIM(PyArrayObject* arr)
和PyArray_SIZE(PyArrayObject* arr)
是numpy Array API中的宏。
编译后,该模块会产生预期的输出,但是,伴随一些编译器警告。因此,我怀疑这里一切正常。
test_modul.c的警告:
test_utilities.h:1:25: warning: declaration of 'struct PyArrayObject'
will not be visible outside of this function [-Wvisibility]
void print_array(struct PyArrayObject **arr);
^
test_modul.c:63:14: warning: incompatible pointer types passing
'PyArrayObject **' (aka 'struct tagPyArrayObject **') to parameter of
type 'struct PyArrayObject **' [-Wincompatible-pointer-types]
do_something(&signal);
^~~~~~~
test_utilities.h:1:41: note: passing argument to parameter 'arr' here
void print_array(struct PyArrayObject **arr);
test_utilities.c的警告:
test_utilities.c:10:20: warning: declaration of 'struct PyArrayObject'
will not be visible outside of this function [-Wvisibility]
do_something(struct PyArrayObject **arr) {
^
test_utilities.c:13:51: warning: incompatible pointer types passing
'struct PyArrayObject *' to parameter of type 'const PyArrayObject *'
(aka 'const struct tagPyArrayObject *') [-Wincompatible-pointer-types]
printf("Array has: %i dimensions.", PyArray_NDIM(*arr));
^~~~
/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-
packages/numpy/core/include/numpy/ndarraytypes.h:1464:35: note: passing
argument to parameter 'arr' here
PyArray_NDIM(const PyArrayObject *arr)
^
test_utilities.c:16:28: warning: incompatible pointer types passing
'struct PyArrayObject *' to parameter of type 'PyArrayObject *' (aka
'struct tagPyArrayObject *') [-Wincompatible-pointer-types]
npy_intp N = PyArray_SIZE(*arr);
^~~~
/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-
packages/numpy/core/include/numpy/ndarrayobject.h:91:59: note: expanded
from macro 'PyArray_SIZE' #define PyArray_SIZE(m)
PyArray_MultiplyList(PyArray_DIMS(m), PyArray_NDIM(m))
^
/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-
packages/numpy/core/include/numpy/ndarraytypes.h:1482:29: note: passing
argument to parameter 'arr' here
PyArray_DIMS(PyArrayObject *arr)
^
我的C语言还不够好,这也许就是为什么我看不到这里发生了什么。 do_something
使用指向结构的指针。因此,在做某事时对arr
的解引用应该使我从test_mod
中的test_mod.c
函数指向PyArrayObject结构的原始指针。这是一个误解吗?如果是,为什么会产生预期的结果?
总结一下,如何正确地将PyArrayObject
传递给C函数,以便没有警告(关于不兼容的指针类型等)?
答案 0 :(得分:0)
再次研究文档后,我发现答案非常简单。只需传递struct指针,例如
do_something(arr);
itsef函数应读取
void do_something(PyArrayObject *arr)
{
int d = PyArray_NDIM(arr));
npy_intp N = PyArray_SIZE(arr);
printf("%i, %li", d, N);
}
此外,在C函数没有返回值的情况下,请不要忘记增加Py_None
的引用计数。因此,C函数的末尾应显示为
Py_INCREF(Py_None);
return Py_None;
一个人也可以使用内置宏Py_RETURN_NONE
,它与以上两行的含义相同。