我正在尝试从应用程序的 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
函数来检索对数组的引用
- 然后使用创建的虚拟 PyObjectPy_BuildValue
来获取数组的 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 结构的字段?例如,particles[0].position_x[0]
从 C 访问就像particles[0]['position_x'][0]
从 Python 端访问一样。
- 这会创建任何副本吗?我正在尝试访问和修改 Python 从 C 分配的内存。