我正在尝试从应用程序的C部分传递和访问用Python创建的Numpy结构化数组。我要使用的这种数组的用法是从Python端创建数组,按原样使用它(仍然是Python),然后在繁重的计算阶段将数组传递给C模块(不使用指针使用副本)这样就可以在C端访问和修改数据。
从Python端,我正在使用自定义的 dtype 创建一个Numpy结构化数组,如下所示,并将其传递给位于简单C扩展中的函数:
Python
import numpy
import cmodule
blocksize=10
numblocks=5
particle_struct_dtype = numpy.dtype([
('position_x', 'f4', (blocksize,)),
('position_y', 'f4', (blocksize,)),
('position_z', 'f4', (blocksize,))
])
particles = numpy.empty(numblocks, dtype=particle_struct_dtype)
cmodule.compute(particles, blocksize, numblocks)
如图所示,我正在创建一个键值数组,其中每个键代表C结构的“字段”,并且该字段的每个值都是浮点数的数组。
然后,在C端,我尝试通过以下方式获取数组:
-首先使用PyArg_ParseTuple
函数检索对数组的引用
-然后使用由Py_BuildValue
创建的虚拟PyObject获取数组dtype的表示形式(结构的类型),随后使用PyArray_AsCArray
C
static PyObject *compute(PyObject *self, PyObject *args)
{
PyArrayObject *particles;
int numblocks, blocksize;
// Parse arguments
if (!PyArg_ParseTuple(args, "O!ii", &PyArray_Type, &particles, &blocksize, &numblocks)) {
Py_RETURN_NONE;
}
PyArray_Descr* arrayDescr;
PyObject* dummy;
dummy = Py_BuildValue("[(s, O), (s, O), (s, O)]", "position_x", (blocksize), "position_y", (blocksize), "position_z", (blocksize));
PyArray_DescrConverter(dummy, &arrayDescr);
struct particles_t *castedParticles;
npy_intp dims[1];
dims[0] = blocksize;
PyArray_AsCArray((PyObject **)&particles, (struct particles_t**)&castedParticles, dims, 1, arrayDescr);
...
}
尽管如此,访问数据时我仍然收到SEGFAULT错误。深入研究错误,我发现数据没有按照我的预期进行转换(转换未正确完成)。
我试图通过传递一个简单的元组数组而不是其中包含更多数组的元组数组来简化示例:
dummy = Py_BuildValue("[(s, s), (s, s), (s, s)]", "position_x", "f4", "position_y", "f4", "position_z", "f4");
PyArray_DescrConverter(dummy, &arrayDescr);
struct simple_particles_t *castedParticles;
npy_intp dims[1];
dims[0] = blocksize;
PyArray_AsCArray((PyObject **)&particles, (struct simple_particles_t**)&castedParticles, dims, 1, arrayDescr);
这似乎可行,我获得了简化结构的数组,每个结构仅包含3个浮点数(每个字段一个),而不是3个浮点数数组。
我的疑问是:
-我想念什么吗?甚至可以将每个字段具有浮点数组的结构化numpy数组转换为C结构数组,以便将每个Python字段映射到C结构的字段?例如,从C访问particles[0].position_x[0]
就像从Python端访问particles[0]['position_x'][0]
。
-这会创建任何副本吗?我正在尝试访问和修改Python从C分配的内存。