通过C访问Numpy Recarray

如果我们有一个Numpy recarray: x = np.array([(1.,2.)], dtype=np.dtype([('a','<f8'),('b','<f8')]))
我们可以在Python中访问其字段,如下所示:
x['a']x['b']
但是,如果这个数组作为PyArrayObject传递给C程序,我们如何访问它的字段?
我知道我们可以通过C获取PyArray_Descr *dtype = PyArray_DTYPE(arr)PyArray_Descr *dtype = PyArray_DTYPE(arr)
PyObject *fields = dtype->fields但是如何用它来访问x['a']处的数据?


我会尽力回答我自己的问题。
看起来你可以使用函数PyObject_GetItem()来访问你的Numpy recarray中的字段。 为了测试这个,我创建了一个包含三个字段的简单数组:
np.dtype([('field1', '<f8', (1,2)), ('field2', '<f8', (2,2)), ('field3', '<f8', (3,1))])
我发送这个数组到我的C ++函数并执行两个循环:每个字段上有一个循环,每个字段中的数组元素(例如x['field1'], x['field2'], x['field3'] )。 在外环中,我使用PyObject_GetItem()来访问每个字段。 代码如下:

C ++代码

#include "Python.h"
#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
#include "arrayobject.h"
#include <cmath>
#include <iostream>
#include <iomanip>
using namespace std;

static PyObject *readarray(PyObject *self, PyObject *args) {
    PyArrayObject *arr, *x2;
    PyArray_Descr *dtype;
    PyObject *names, *name, *x1 = NULL;
    Py_ssize_t N, i;
    NpyIter *iter;
    NpyIter_IterNextFunc *iternext;
    double **dataptr;
    npy_intp index;

    if (!PyArg_ParseTuple(args, "O!", &PyArray_Type, &arr)) {
        return NULL;
    }
    dtype = PyArray_DTYPE(arr);
    names = dtype->names;
    if (names != NULL) {
        names = PySequence_Fast(names, NULL);
        N = PySequence_Fast_GET_SIZE(names);
        for (i=0; i<N; i++) {
            name = PySequence_Fast_GET_ITEM(names, i);
            cout << setw(7) << left << PyString_AsString(name);
            x1 = PyObject_GetItem((PyObject *) arr, name);
            x2 = (PyArrayObject *) x1;
            dtype = PyArray_DTYPE(x2);
            iter = NpyIter_New(x2, NPY_ITER_READONLY, NPY_KEEPORDER, NPY_SAME_KIND_CASTING, dtype);
            if (iter == NULL) {return NULL;}
            dataptr = (double **) NpyIter_GetDataPtrArray(iter);
            iternext = NpyIter_GetIterNext(iter, NULL);
            do {
                index = NpyIter_GetIterIndex(iter);
                if (index==0) {
                    cout << setw(6) << right << index << setw(9) << setiosflags(ios::fixed) << setprecision(4) <<**dataptr << endl;
                } else {
                    cout << "       " << setw(6) << right << index << setw(9) << setiosflags(ios::fixed) << setprecision(4) << **dataptr << endl;
                }
            } while (iternext(iter));
        }
        NpyIter_Deallocate(iter);
    }
    return Py_BuildValue("i", 0);
}

static PyMethodDef pyproj4methods[] = {
    {"readarray", readarray, METH_VARARGS, "Documentation"},
    {NULL, NULL, 0, NULL}
};

PyMODINIT_FUNC initpyproj4(void) {
    Py_InitModule("pyproj4", pyproj4methods);
    import_array();
}


Python代码

import numpy as np
import pyproj4 as p4
np.random.seed(22)

## Python Implementation ##
dt = np.dtype([('field1', '<f8', (1,2)), ('field2', '<f8', (2,2)), ('field3', '<f8', (3,1))])
x = np.zeros(2, dtype=dt)

for name in x.dtype.names:
    m,n,p = x[name].shape
    x[name] = np.random.randn(m,n,p)
    it = np.nditer(x[name], ['c_index'], ['readonly'])
    for num in it:
        if it.index==0:
            print '{0:6s} {1:6d}  {2: 2.4f}'.format(name, it.index, num.item())
        else:
            print '{0:6s} {1:6d}  {2: 2.4f}'.format(' ', it.index, num.item())
print '-----------------------'
## C-API Implementation ##
p4.readarray(x)


两种情况下的输出如下所示:

field1      0  -0.0919
            1  -1.4634
            2   1.0818
            3  -0.2393
field2      0  -0.4911
            1  -1.0023
            2   0.9188
            3  -1.1036
            4   0.6265
            5  -0.5615
            6   0.0289
            7  -0.2308
field3      0   0.5878
            1   0.7523
            2  -1.0585
            3   1.0560
            4   0.7478
            5   1.0647

如果您知道更好的方法来完成此任务,请不要犹豫,发布您的解决方案。

链接地址: http://www.djcxy.com/p/74705.html

上一篇: Access a Numpy Recarray via the C

下一篇: How do I create a parallel loop?