python - (Numpy C API)迭代单个数组:NpyIter 与 for 循环(使用 PyArray_DATA)
问题描述
我正在为 python 模块编写一些 C 扩展代码。我要写的函数是(在python中)
output = 1./(1. + input)
其中input
是任何形状的 numpy 数组。
最初我使用的是NpyIter_MultiNew
:
static PyObject *
helper_calc1(PyObject *self, PyObject *args){
PyObject * input;
PyObject * output = NULL;
if (!PyArg_ParseTuple(args, "O", &input)){
return NULL;
}
// -- input -----------------------------------------------
PyArrayObject * in_arr;
in_arr = (PyArrayObject *) PyArray_FROM_OTF(input, NPY_DOUBLE, NPY_ARRAY_IN_ARRAY);
if (in_arr == NULL){
goto fail;
}
// -- set up iterator -------------------------------------
PyArrayObject * op[2];
npy_uint32 op_flags[2];
npy_uint32 flags;
op[0] = in_arr;
op_flags[0] = NPY_ITER_READONLY;
op[1] = NULL;
op_flags[1] = NPY_ITER_WRITEONLY | NPY_ITER_ALLOCATE;
flags = NPY_ITER_EXTERNAL_LOOP | NPY_ITER_BUFFERED | NPY_ITER_GROWINNER;
NpyIter * iter = NpyIter_MultiNew(2, op,
flags, NPY_KEEPORDER, NPY_NO_CASTING,
op_flags, NULL);
if (iter == NULL){
goto fail;
};
NpyIter_IterNextFunc * iternext = NpyIter_GetIterNext(iter, NULL);
if (iternext == NULL){
NpyIter_Deallocate(iter);
goto fail;
};
// -- iterate ---------------------------------------------
npy_intp count;
char ** dataptr = NpyIter_GetDataPtrArray(iter);
npy_intp * strideptr = NpyIter_GetInnerStrideArray(iter);
npy_intp * innersizeptr = NpyIter_GetInnerLoopSizePtr(iter);
do {
count = *innersizeptr;
while (count--){
*(double *) dataptr[1] = 1. / (1. + *(double *)dataptr[0]);
dataptr[0] += strideptr[0];
dataptr[1] += strideptr[1];
}
} while (iternext(iter));
output = NpyIter_GetOperandArray(iter)[1];
if (NpyIter_Deallocate(iter) != NPY_SUCCEED){
goto fail;
}
Py_DECREF(in_arr);
return output;
fail:
Py_XDECREF(in_arr);
Py_XDECREF(output);
return NULL;
}
但是,由于这只是一个数组(即我不需要担心广播多个数组),有什么理由我不能自己使用循环和数组大小来迭代数据PyArray_DATA
吗for
?
static PyObject *
helper_calc2(PyObject *self, PyObject *args){
PyObject * input;
PyObject * output = NULL;
if (!PyArg_ParseTuple(args, "O", & in)){
return NULL;
}
// -- input -----------------------------------------------
PyArrayObject * in_arr;
in_arr = (PyArrayObject *) PyArray_FROM_OTF(input, NPY_DOUBLE, NPY_ARRAY_IN_ARRAY);
if (in_arr == NULL){
Py_XDECREF(in_arr);
return NULL;
}
int ndim = PyArray_NDIM(in_arr);
npy_intp * shape = PyArray_DIMS(in_arr);
int size = (int) PyArray_SIZE(in_arr);
double * in_data = (double *) PyArray_DATA(in_arr);
output = PyArray_SimpleNew(ndim, shape, NPY_DOUBLE);
double * out_data = (double *) PyArray_DATA((PyArrayObject *) output);
for (int i = 0; i < size; i++){
out_data[i] = 1. / (1. + in_data[i]);
}
Py_DECREF(in_arr);
return output;
fail:
Py_XDECREF(in_arr);
Py_XDECREF(output);
return NULL;
}
第二个版本运行速度更快,代码更短。
PyArray_DATA
使用for
循环而不是循环时我需要注意任何危险NpyIter_MultiNew
吗?
从PyArray_DATA
文档中:
如果您不能保证一个连续和/或对齐的数组,那么请确保您了解如何访问数组中的数据以避免内存和/或对齐问题。
但我相信这是由国旗PyArray_FROM_OTF
处理的。NPY_ARRAY_IN_ARRAY
解决方案
在这种情况下你应该没问题。就像您提到NPY_ARRAY_IN_ARRAY
的PyArray_FROM_OTF
那样,解决了这个问题,并且由于您将数据指针转换为正确的类型,所以应该没问题。但是,一般来说,您似乎知道,如果您直接从 Python 代码中接受 NumPy 数组,则不能使用这种方法。
快乐的 C 扩展写作。
推荐阅读
- c# - 如何使用 Windows 窗体打印印地语文本?
- python - 从网页获取信息并使用 pandas 和 bs4 写入 .xls 文件
- android - 为什么上下文为空?
- java - 如何调用从多个线程获取信息的实时日志模拟器
- django - 为什么不先使用 django.setup() 就无法将模型导入 python 脚本
- php - 使用 php 抓取 javascript 生成的网站
- android - 如何在android studio中修复“删除线视图”
- .net-core - 多目标 .NET Core 控制台的 Azure DevOps (VSTS) 托管 macOS 代理失败
- database - postgresql 中声明时间值的总和
- android - 如何从 Firebase 消息服务类调用 MainActivity 类中的方法?