如何将动态分配的 C 数组转换为 Numpy 数组并在 C 扩展模块中将其返回给 Python

问题描述 投票:0回答:1

所以我在这里的线程中发现了类似的问题,但我一直无法找到适合我的解决方案。

我正在使用 Python 3.9 在 Visual Studio 2022 中构建 Python 的 C 扩展模块。该模块将 numpy 数组作为输入并返回 numpy 数组。现在,我只是让它读取输入数组的形状,并用它来决定要创建多大的输出数组。如果输入是 shape (row, col),那么输出将是 shape (2, row, col)。

我动态分配一个带有

2*row*col
元素的 C 数组。

以下全部在函数内

static PyObject* transform(PyObject* self, PyObject* args) {}

import_array();
PyObject* data_obj;
PyArrayObject* data_array;


if (!PyArg_ParseTuple(args, "O", &data_obj)) {
    return NULL;
}

data_array = (PyArrayObject*)PyArray_FROM_OTF(data_obj, NPY_DOUBLE, NPY_ARRAY_IN_ARRAY);

if (data_array == NULL) {
    PyErr_SetString(PyExc_TypeError, "The data input must be a NumPy Array (2D or 3D)");
    return NULL;
}

int ndim = PyArray_NDIM(data_array);
npy_intp* data_shape = PyArray_SHAPE(data_array);

size_t rows, columns;
rows = data_shape[0];
columns = data_shape[1];

double* r_arr = (double*)malloc((rows * columns * 2) * sizeof(double));
if (r_arr == NULL) {
    PyErr_SetString(PyExc_ValueError, "Failed to allocate memory to arrays.");
    Py_DECREF(data_array);
}

然后,我循环行和列,并进行多次计算,在每行和每列生成两个数字,并将它们存储为

r_arr[rr * rows + cc]
r_arr[rr * rows + cc + rows * columns]

for (size_t cc = 0; cc < columns; ++cc) {
    // some calculation
    for (size_t rr = 0; rr < rows; ++rr) {
        // some calculation
        r_arr[rr * rows + cc] = result1;
        r_arr[rr * rows + cc + rows * columns] = result2;
        PySys_WriteStdout("%f, %f\n", r_arr[rr * rows + cc], r_arr[rr * rows + cc + rows * columns]);
    }
}

最后我想把

r_arr
转成numpy数组返回Python。我在这里尝试了很多事情,但这是基于在这里阅读其他线程的当前状态。

npy_intp dims[3] = { 2, rows, columns };
PyObject* r_obj = (PyArrayObject *)PyArray_SimpleNewFromData(3, dims, NPY_DOUBLE, r_arr);

if (r_obj == NULL) {
    PyErr_Print("Failed to create internal arrays. Likely due to data input being incorrect shape.");
    return NULL;
}

Py_DECREF(data_array);
free(x);
free(y);
//free(r_arr);
PyArray_ENABLEFLAGS(r_obj, NPY_ARRAY_OWNDATA);
PySys_WriteStdout("Returning result\n");
return Py_BuildValue("O", r_obj);

在 Python 中,当我创建形状为 (5, 10) 的数组并将其用作输入时,我得到以下结果。嵌套循环打印出正确的值,但返回的数组似乎是我使用

np.empty((2, 5, 10))
时会得到的结果。

我还尝试使用

PyArray_SimpleNewFromData()
创建带有
2*rows*columns
元素的一维 numpy 数组,但这没有什么区别。

输出:

0.023581, 4.986665
0.021305, 3.986672
0.018796, 2.986680
0.016282, 1.986689
0.014207, 0.986699
-0.986851, 4.986664
-0.986798, 3.986672
-0.986746, 2.986680
-0.986700, 1.986689
-0.986667, 0.986699
-1.986746, 4.986662
-1.986718, 3.986670
-1.986691, 2.986679
-1.986666, 1.986688
-1.986648, 0.986699
-2.986705, 4.986660
-2.986685, 3.986668
-2.986665, 2.986677
-2.986646, 1.986687
-2.986632, 0.986698
-3.986679, 4.986656
-3.986662, 3.986665
-3.986645, 2.986675
-3.986629, 1.986685
-3.986616, 0.986697
-4.986658, 4.986651
-4.986642, 3.986661
-4.986626, 2.986672
-4.986611, 1.986683
-4.986599, 0.986696
-5.986637, 4.986645
-5.986622, 3.986657
-5.986607, 2.986669
-5.986592, 1.986681
-5.986579, 0.986695
-6.986616, 4.986638
-6.986601, 3.986651
-6.986586, 2.986664
-6.986571, 1.986678
-6.986558, 0.986694
-7.986593, 4.986630
-7.986578, 3.986645
-7.986563, 2.986660
-7.986547, 1.986675
-7.986533, 0.986692
-8.986567, 4.986621
-8.986552, 3.986637
-8.986536, 2.986654
-8.986520, 1.986672
-8.986505, 0.986690
Returning result
array([[[ 1.14460020e-311,  1.14458244e-311,  1.14458542e-311,
          1.14478895e-311,  1.14478881e-311,  1.14478881e-311,
          1.14478893e-311,  1.14478894e-311,  1.14458542e-311,
          1.14478894e-311],
        [-8.98656729e+000,  1.14478893e-311,  1.14458542e-311,
          1.14478894e-311,  1.14478894e-311, -8.98655189e+000,
          1.14458542e-311,  1.14478895e-311,  1.14478895e-311,
          1.14478894e-311],
        [-8.98653594e+000,  1.14478884e-311,  1.14478894e-311,
          1.14478894e-311,  1.14478894e-311, -8.98652003e+000,
          1.14478884e-311,  1.14478894e-311,  1.14478894e-311,
          1.14478894e-311],
        [-8.98650487e+000,  1.14478893e-311,  1.14478895e-311,
          1.14478894e-311,  1.14478894e-311,  1.14478894e-311,
          1.14478884e-311,  1.14478894e-311,  1.14478894e-311,
          1.14478894e-311],
        [ 1.14478894e-311,  1.14478893e-311,  1.14478894e-311,
          1.14478894e-311,  1.14478894e-311,  1.14478894e-311,
          1.14478894e-311,  1.14478895e-311,  1.14478895e-311,
          1.14478895e-311]],

       [[ 1.14478894e-311,  1.14458542e-311,  1.14478895e-311,
          1.14478895e-311,  1.14478893e-311,  1.14478895e-311,
          1.14478893e-311,  1.14458542e-311,  1.14478884e-311,
          1.14478893e-311],
        [ 4.98662116e+000,  1.14478895e-311,  1.14478893e-311,
          1.14478894e-311,  1.14478895e-311,  3.98663750e+000,
          1.14478884e-311,  1.14458542e-311,  1.14478893e-311,
          1.14458542e-311],
        [ 2.98665407e+000,  1.14478895e-311,  1.14478895e-311,
          1.14478895e-311,  1.14478895e-311,  1.98667152e+000,
          1.14458542e-311,  1.14458542e-311,  1.14478895e-311,
          1.14478895e-311],
        [ 9.86690488e-001,  1.14478895e-311,  1.14478895e-311,
          1.14458542e-311,  1.14478884e-311,  1.14458542e-311,
          1.14478894e-311,  1.14478893e-311,  1.14458542e-311,
          1.14478895e-311],
        [ 1.14478895e-311,  1.14478884e-311,  1.14478893e-311,
          1.14478893e-311,  1.14458542e-311,  1.14478895e-311,
          9.38662745e-097,  2.07712408e-308,  1.14478658e-311,
          1.14458243e-311]]])
python arrays c numpy
1个回答
0
投票

这是我的解决方案以及一些其他修复。 OP中的上述代码没有正确从数组中获取数据(计算不依赖于元素的实际值,只依赖于形状)。它也无法正确计算索引。然而,解决方案的关键是我将数组实例化为带有

PyArrayObject
PyArray_ZEROS()
,然后从中获取数据进行操作。

PyArrayObject* data_array_obj;

if (!PyArg_ParseTuple(args, "O", &data_array_obj)) {
    return NULL;
}

if (data_array_obj == NULL) {
    PyErr_SetString(PyExc_TypeError, "The data input must be a NumPy Array");
    return NULL;
}

// Determine dimensionality and shape
int64_t ndim = PyArray_NDIM(data_array_obj);
size_t* data_shape = PyArray_SHAPE(data_array_obj);

if (ndim != 2) {
    PyErr_SetString(PyExc_TypeError, "The input NumPy Array must be 2D");
    return NULL;
}

size_t rows, columns;
rows = data_shape[0];
columns = data_shape[1];


// Get data from input array
double* data = PyArray_DATA(data_array_obj);

// Instantiate output array
npy_intp dims[3] = { 2, rows, columns };
PyArrayObject* r_obj_array = PyArray_ZEROS(3, dims, NPY_DOUBLE, 0);
double* r_data = PyArray_DATA(r_obj_array);


for (size_t cc = 0; cc < columns; ++cc) {
    // some calculation
    for (size_t rr = 0; rr < rows; ++rr) {
        // some calculation
        r_data[rr * columns + cc] = result1;
        r_data[rr * columns + cc + rows * columns] = result2;
    }
}

Py_DECREF(data_array);
return r_obj_array;
© www.soinside.com 2019 - 2024. All rights reserved.