首页 > 解决方案 > Numpy Python/C API - PyArray_SimpleNewFromData 挂起

问题描述

我正在为更复杂的任务找出 Python/C API。最初,我写了一个简单的例子,添加了两个形状 = (2,3) 和类型 = float32 的 ndarray。

我能够将两个 numpy 数组传递给 c 函数,读取它们的维度和数据并对数据执行自定义添加。但是当我尝试使用 PyArray_SimpleNewFromData 包装生成的数据时,代码挂起(返回 NULL?)

要复制问题,请在文件夹中创建三个文件:mymath.c、setup.py、test.py,如下所示并运行 test.py(它运行 setup.py 来编译和安装模块,然后运行一个简单的测试)。

我在 anaconda 环境中的 windows 中使用 python。我是 Python/C API 的新手。因此,任何帮助将不胜感激。

​</p>

// mymath.c

#include <Python.h>
#include <stdio.h>
#include "numpy/arrayobject.h"
#include "numpy/npy_math.h"
#include <math.h>
#include <omp.h>

/*
  C functions
*/

float* arr_add(float* d1, float* d2, int M, int N){

  float * result = (float *) malloc(sizeof(float)*M*N);

  for (int m=0; m<M; m++)
    for (int n=0; n<N; n++)
      result [m*N+ n] = d1[m*N+ n] + d2[m*N+ n];

  return result;
}

/*
  Unwrap apply and wrap pyObjects
*/

void capsule_cleanup(PyObject *capsule) {
  void *memory = PyCapsule_GetPointer(capsule, NULL);
  free(memory);
}

// add two 2d arrays (float32)
static PyObject *arr_add_fn(PyObject *self, PyObject *args)
{
  PyArrayObject *arr1, *arr2;

  if (!PyArg_ParseTuple(args, "OO", &arr1, &arr2))
    return NULL;
  
  // get data as flat list
  float *d1, *d2;
  d1 = (float *) arr1->data;
  d2 = (float *) arr2->data;

  int M, N;
  M = (int)arr1->dimensions[0];
  N = (int)arr1->dimensions[1];

  printf("Dimensions, %d, %d \n\n", M,N);

  PyObject *result, *capsule;
  npy_intp dim[2];
  dim[0] = M;
  dim[1] = N;

  float * d3 = arr_add(d1, d2, M, N);

  result = PyArray_SimpleNewFromData(2, dim, NPY_FLOAT, (void *)d3);
  if (result == NULL)
    return NULL;

  // -----------This is not executed. code hangs--------------------
  for (int m=0; m<M; m++)
    for (int n=0; n<N; n++)
      printf("%f \n", d3[m*N+n]);

  capsule = PyCapsule_New(d3, NULL, capsule_cleanup);
  PyArray_SetBaseObject((PyArrayObject *) result, capsule);
  return result;
}

/*
  Bundle functions into module
*/

static PyMethodDef MyMethods [] ={
  {"arr_add", arr_add_fn, METH_VARARGS, "Array Add two numbers"},
  {NULL,NULL,0,NULL}
};

/*
  Create module
*/

static struct PyModuleDef mymathmodule = {
  PyModuleDef_HEAD_INIT,
  "mymath", "My doc of mymath", -1, MyMethods
};

PyMODINIT_FUNC PyInit_mymath(void){
  return PyModule_Create(&mymathmodule);
}

​</p>

# setup.py

from distutils.core import setup, Extension
import numpy

module1 = Extension('mymath',
        sources = ['mymath.c'],
        # define_macros = [('NPY_NO_DEPRECATED_API', 'NPY_1_7_API_VERSION')],
        include_dirs=[numpy.get_include()],
        extra_compile_args = ['-fopenmp'],
        extra_link_args = ['-lgomp'])

setup (name = 'mymath',
        version = '1.0',
        description = 'My math',
        ext_modules = [module1])

​</p>

# test.py

import os

os.system("python .\setup.py install")

import numpy as np
import mymath

a = np.arange(6,dtype=np.float32).reshape(2,3)
b = np.arange(6,dtype=np.float32).reshape(2,3)

c = mymath.arr_add(a,b)
print(c)

标签: pythonnumpycpythonpython-c-api

解决方案


推荐阅读