我有一些用Python写的代码,其输出是一个numpy数组,现在我想将该输出发送到 C ++ 代码,其中将执行大部分计算.
I have some code writen in Python for which the output is a numpy array, and now I want to send that output to C++ code, where the heavy part of the calculations will be performed.
我曾尝试使用cython的 public cdef ,但是我在某些问题上运行.多谢您的协助!这是我的代码:
I have tried using cython's public cdef, but I am running on some issues. I would appreciate your help! Here goes my code:
pymodule.pyx :
from pythonmodule import result # result is my numpy array import numpy as np cimport numpy as np cimport cython @cython.boundscheck(False) @cython.wraparound(False) cdef public void cfunc(): print 'I am in here!!!' cdef np.ndarray[np.float64_t, ndim=2, mode='c'] res = result print res一旦被cythonized,我会打电话给
Once this is cythonized, I call:
pymain.c :
#include <Python.h> #include <numpy/arrayobject.h> #include "pymodule.h" int main() { Py_Initialize(); initpymodule(); test(2); Py_Finalize(); } int test(int a) { Py_Initialize(); initpymodule(); cfunc(); return 0; }我在 C ++ 处得到 result 变量的 NameError .我尝试使用指针定义它并从其他函数间接调用它,但是数组仍然不可见.我很确定答案很简单,但我只是不明白.感谢您的帮助!
I am getting a NameError for the result variable at C++. I have tried defining it with pointers and calling it indirectly from other functions, but the array remains invisible. I am pretty sure the answer is quite simple, but I just do not get it. Thanks for your help!
推荐答案简短回答
NameError是由于Python找不到模块而导致的,因此工作目录不会自动添加到您的 PYTHONPATH .使用 setenv 与 C/C ++ 代码中的 setenv("PYTHONPATH",.",1); 一起解决.
Short Answer
The NameError was cause by the fact that Python couldn't find the module, the working directory isn't automatically added to your PYTHONPATH. Using setenv with setenv("PYTHONPATH", ".", 1); in your C/C++ code fixes this.
显然,有一种简单的方法可以做到这一点.使用包含已创建数组的python模块 pythonmodule.py :
There's an easy way to do this, apparently. With a python module pythonmodule.py containing an already created array:
import numpy as np result = np.arange(20, dtype=np.float).reshape((2, 10))您可以使用 public 关键字.通过添加一些辅助功能,通常不需要触摸Python或Numpy C-API :
You can structure your pymodule.pyx to export that array by using the public keyword. By adding some auxiliary functions, you'll generally won't need to touch neither the Python, nor the Numpy C-API:
from pythonmodule import result from libc.stdlib cimport malloc import numpy as np cimport numpy as np cdef public np.ndarray getNPArray(): """ Return array from pythonmodule. """ return <np.ndarray>result cdef public int getShape(np.ndarray arr, int shape): """ Return Shape of the Array based on shape par value. """ return <int>arr.shape[1] if shape else <int>arr.shape[0] cdef public void copyData(float *** dst, np.ndarray src): """ Copy data from src numpy array to dst. """ cdef float **tmp cdef int i, j, m = src.shape[0], n=src.shape[1]; # Allocate initial pointer tmp = <float **>malloc(m * sizeof(float *)) if not tmp: raise MemoryError() # Allocate rows for j in range(m): tmp[j] = <float *>malloc(n * sizeof(float)) if not tmp[j]: raise MemoryError() # Copy numpy Array for i in range(m): for j in range(n): tmp[i][j] = src[i, j] # Assign pointer to dst dst[0] = tmp函数 getNPArray 和 getShape 分别返回数组及其形状.添加了 copyData 以便提取 ndarray.data 并进行复制,这样您就可以完成Python的工作,而无需初始化解释器.
Function getNPArray and getShape return the array and its shape, respectively. copyData was added in order to just extract the ndarray.data and copy it so you can then finalize Python and work without having the interpreter initialized.
一个示例程序(在 C 中, C ++ 应该看起来完全相同)看起来像这样:
A sample program (in C, C++ should look identical) would look like this:
#include <Python.h> #include "numpy/arrayobject.h" #include "pyxmod.h" #include <stdio.h> void printArray(float **arr, int m, int n); void getArray(float ***arr, int * m, int * n); int main(int argc, char **argv){ // Holds data and shapes. float **data = NULL; int m, n; // Gets array and then prints it. getArray(&data, &m, &n); printArray(data, m, n); return 0; } void getArray(float ***data, int * m, int * n){ // setenv is important, makes python find // modules in working directory setenv("PYTHONPATH", ".", 1); // Initialize interpreter and module Py_Initialize(); initpyxmod(); // Use Cython functions. PyArrayObject *arr = getNPArray(); *m = getShape(arr, 0); *n = getShape(arr, 1); copyData(data, arr); if (data == NULL){ //really redundant. fprintf(stderr, "Data is NULL\n"); return ; } Py_DECREF(arr); Py_Finalize(); } void printArray(float **arr, int m, int n){ int i, j; for(i=0; i < m; i++){ for(j=0; j < n; j++) printf("%f ", arr[i][j]); printf("\n"); } }始终记得设置:
setenv("PYTHONPATH", ".", 1);之前,您调用 Py_Initialize ,以便Python可以在工作目录中找到模块.
before you call Py_Initialize so Python can find modules in the working directory.
其余的非常简单.它可能需要进行一些其他的错误检查,并且一定需要一个函数来释放分配的内存.
The rest is pretty straight-forward. It might need some additional error-checking and definitely needs a function to free the allocated memmory.
以您尝试的方式进行操作很麻烦,而不是值得的,使用 numpy.save 将数组保存在 npy 二进制文件中,然后使用一些 为您读取该文件的C ++库 .
Doing it the way you are attempting is way hassle than it's worth, you would probably be better off using numpy.save to save your array in a npy binary file and then use some C++ library that reads that file for you.
更多推荐
将numpy数组传递给C ++
发布评论