如何在C语言中访问NumPy record(记录)的内容?
问题背景
假设我创建了如下代码:
import numpy as np descriptor = np.dtype([ ('left', np.double, 3), ('center', np.double, 3), ('right', np.double, 3), ]) value = np.zeros(10, dtype=descriptor)
可以验证value是由90个double类型数据组成的连续内存块。修改value[3]后,原数组也会同步变化,说明value[3]是指向该连续内存中某一位置的数据结构。
但value[3]究竟是什么?若将任意value[i]传入C函数,C代码该如何找到该元素对应的9个内存位置?对于普通非记录子数组,可使用PyArray_DATA宏获取数据位置,但尚未找到适用于NumPy Records的对应方法。
该元素的方法解析顺序(mro())如下:
[numpy.record, numpy.void, numpy.flexible, numpy.generic, object]
解答
1. value[i]的本质
value[i]是**numpy.record类型的标量对象**,它继承自numpy.void(属于NumPy的灵活类型numpy.flexible),本质是原数组对应位置内存的视图:
- 它不独立分配内存,直接引用原数组连续内存块中对应单个record的起始位置
- 单个
numpy.record的大小等于定义的descriptor总字节数(此处为3*8 + 3*8 +3*8 = 72字节,对应9个double) - 修改该标量的字段(如
value[i]['left'][0] = 1.0)会直接修改原数组的内存,因此原数组会同步变化
2. C语言中访问value[i]的内存位置
在NumPy C API中,numpy.record属于void类型的标量对象,可通过以下步骤获取其对应的内存指针:
步骤1:验证对象类型
首先确认传入的Python对象是numpy.void类型的标量:
#include <numpy/arrayobject.h> // 假设传入参数为obj if (!PyArrayScalar_Check(obj)) { PyErr_SetString(PyExc_TypeError, "Input must be a NumPy scalar"); return NULL; } PyArray_Descr *descr = PyArrayScalar_DESCR(obj); if (descr->type_num != NPY_VOID) { PyErr_SetString(PyExc_TypeError, "Input must be a NumPy void/record scalar"); return NULL; }
步骤2:获取内存起始地址
将对象转换为PyArrayScalarObject指针,直接访问其data成员,该成员即为对应record内存块的起始地址:
PyArrayScalarObject *scalar = (PyArrayScalarObject *)obj; // 转换为double指针,匹配record的内部数据类型 double *record_data = (double *)scalar->data; // 直接访问9个double: // record_data[0]~record_data[2] → 'left'字段的3个值 // record_data[3]~record_data[5] → 'center'字段的3个值 // record_data[6]~record_data[8] → 'right'字段的3个值
补充:按字段名访问(可选)
如果需要按字段名精准访问,可通过descriptor获取字段的偏移量:
// 获取'left'字段的内存偏移量 npy_intp left_offset; if (PyArrayDescr_GetFieldOffset(descr, "left", &left_offset) < 0) { return NULL; } double *left_data = (double *)((char *)scalar->data + left_offset); // left_data[0], left_data[1], left_data[2] 即为'left'字段的三个值
内容的提问来源于stack exchange,提问作者Frank Yellin
相关产品推荐
相关产品推荐

