在 C++ 中嵌入 python/numpy
Embed python / numpy in C++
我正在尝试在我的 C++ 应用程序中使用 python 3(带有 numpy)。
这需要将 C++ 数组发送到 python,执行计算,然后在 C++ 中检索结果。
为此,我基于此处讨论的代码:
https://codereview.stackexchange.com/questions/92266/sending-a-c-array-to-python-numpy-and-back/92353#92353
还有这里:
Sending a C++ array to Python and back (Extending C++ with Numpy).
虽然代码审查 post 中的示例基本有效,但我在修改 python 和 C++ 脚本时遇到了 return 值的问题:当我尝试 return 在 python 中创建的变量结果是 nan 的向量而不是预期的计算。
我的猜测是该对象不知何故超出了范围,但我无法解决这个问题。
我在名为 mymodule.py:
的文件中使用以下 python 脚本
import numpy
def array_tutorial(a):
print("array_tutorial - python")
print(a)
print("")
firstRow = a[0,:]
#beta = numpy.array([[10,20,30],[10,20,30],[10,20,30]])
#firstRow = beta[0,:]
return firstRow
def myfunction():
beta = numpy.array([[1,2,3],[1,2,3],[1,2,3]])
print("myfunction - python")
print(beta)
print("")
firstRow = beta[0,:]
return firstRow
我的 C++ 代码在文件 numpy_cpp.cpp 中,它是对代码审查 post 的已接受答案的略微更改和简化版本。
#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
#include <stdio.h>
#include <iostream>
#include <stdlib.h>
#include <Python.h>
#include "numpy/arrayobject.h"
int main(int argc, char* argv[])
{
setenv("PYTHONPATH", ".", 0);
Py_Initialize();
import_array();
// Build the 2D array in C++
const int SIZE = 3;
npy_intp dims[2]{SIZE, SIZE};
const int ND = 2;
long double(*c_arr)[SIZE]{ new long double[SIZE][SIZE] };
for (int i = 0; i < SIZE; i++){
for (int j = 0; j < SIZE; j++){
c_arr[i][j] = i + j;}
}
// Convert it to a NumPy array.
PyObject *pArray = PyArray_SimpleNewFromData(ND, dims, NPY_LONGDOUBLE, reinterpret_cast<void*>(c_arr));
// import mymodule
const char *module_name = "mymodule";
PyObject *pName = PyUnicode_FromString(module_name);
PyObject *pModule = PyImport_Import(pName);
Py_DECREF(pName);
// import function
const char *func_name = "array_tutorial";
PyObject *pFunc = PyObject_GetAttrString(pModule, func_name);
PyObject *pReturn = PyObject_CallFunctionObjArgs(pFunc, pArray, NULL);
PyArrayObject *np_ret = reinterpret_cast<PyArrayObject*>(pReturn);
// Convert back to C++ array and print.
int len = PyArray_SHAPE(np_ret)[0];
long double* c_out;
c_out = reinterpret_cast<long double*>(PyArray_DATA(np_ret));
std::cout << "Printing output array - C++" << std::endl;
for (int i = 0; i < len; i++){
std::cout << c_out[i] << ' ';
}
std::cout << std::endl << std::endl;
// import function without arguments
const char *func_name2 = "myfunction";
PyObject *pFunc2 = PyObject_GetAttrString(pModule, func_name2);
PyObject *pReturn2 = PyObject_CallFunctionObjArgs(pFunc2, NULL);
PyArrayObject *np_ret2 = reinterpret_cast<PyArrayObject*>(pReturn2);
// convert back to C++ array and print
int len2 = PyArray_SHAPE(np_ret2)[0];
long double* c_out2;
c_out2 = reinterpret_cast<long double*>(PyArray_DATA(np_ret2));
std::cout << "Printing output array 2 - C++" << std::endl;
for (int i = 0; i < len2; i++){
std::cout << c_out2[i] << ' ';
}
std::cout << std::endl << std::endl;
Py_Finalize();
return 0;
}
与接受的答案相比,我不得不添加
setenv("PYTHONPATH", ".", 0);
为了确保找到 python 脚本,我为没有输入参数的函数 "myfunction" 添加了第二个函数调用,并删除了一些错误处理。
我在 Ubuntu 16.10 并使用
g++ -Wall numpy_cpp.cpp -I/usr/include/python3.5m/ -lpython3.5m
编译和 link(除 import_array() 发出的一个警告外一切正常)。我的目标是 python 3.
运行 但是该程序给出以下控制台输出:
array_tutorial - python
[[ 0.0 1.0 2.0]
[ 1.0 2.0 3.0]
[ 2.0 3.0 4.0]]
Printing output array - C++
0 1 2
myfunction - python
[[1 2 3]
[1 2 3]
[1 2 3]]
Printing output array 2 - C++
nan nan nan
这是给我带来麻烦的最后一个输出,其中 python return 是在 python 脚本中设置的 numpy 数组的第一行。
从 python print 语句来看,numpy 数组似乎很好(不是 nan),但一旦它被引用到 C++ 中,事情就会发生变化。
如果我在 array_tutorial 函数中取消注释 return 语句上方的两行,我会得到与第一个函数调用相同(令人失望)的结果。
因此,我的问题是如何在 C++ 中获取正确的值而不让对象(可能)超出范围?
对于冗长的 post,我深表歉意,在此先感谢您的帮助!
编辑: 正如下面 lomereiter 所指出的,python 中的 numpy 数组应该在设置时牢记数据类型。
这解决了问题。
一个更好的 python 脚本输出接收数组的数据类型并指定声明数组的数据类型是:
import numpy
def array_tutorial(a):
print("array_tutorial - python")
print(a)
print(numpy.dtype(a[0,0]))
print("")
firstRow = a[0,:]
#beta = numpy.array([[10,20,30],[10,20,30],[10,20,30]],dtype=numpy.float128)
#firstRow = beta[0,:]
return firstRow
def myfunction():
beta = numpy.array([[1,2,3],[1,2,3],[1,2,3]],dtype=numpy.float128)
print("myfunction - python")
print(beta)
print("")
firstRow = beta[0,:]
return firstRow
在 Python 代码中创建数组时应指定 dtype。您在 C++ 代码中转换为 long double,而 dtype 被推断为 int64(在 64 位平台上)
我正在尝试在我的 C++ 应用程序中使用 python 3(带有 numpy)。 这需要将 C++ 数组发送到 python,执行计算,然后在 C++ 中检索结果。 为此,我基于此处讨论的代码: https://codereview.stackexchange.com/questions/92266/sending-a-c-array-to-python-numpy-and-back/92353#92353 还有这里: Sending a C++ array to Python and back (Extending C++ with Numpy).
虽然代码审查 post 中的示例基本有效,但我在修改 python 和 C++ 脚本时遇到了 return 值的问题:当我尝试 return 在 python 中创建的变量结果是 nan 的向量而不是预期的计算。 我的猜测是该对象不知何故超出了范围,但我无法解决这个问题。
我在名为 mymodule.py:
的文件中使用以下 python 脚本import numpy
def array_tutorial(a):
print("array_tutorial - python")
print(a)
print("")
firstRow = a[0,:]
#beta = numpy.array([[10,20,30],[10,20,30],[10,20,30]])
#firstRow = beta[0,:]
return firstRow
def myfunction():
beta = numpy.array([[1,2,3],[1,2,3],[1,2,3]])
print("myfunction - python")
print(beta)
print("")
firstRow = beta[0,:]
return firstRow
我的 C++ 代码在文件 numpy_cpp.cpp 中,它是对代码审查 post 的已接受答案的略微更改和简化版本。
#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
#include <stdio.h>
#include <iostream>
#include <stdlib.h>
#include <Python.h>
#include "numpy/arrayobject.h"
int main(int argc, char* argv[])
{
setenv("PYTHONPATH", ".", 0);
Py_Initialize();
import_array();
// Build the 2D array in C++
const int SIZE = 3;
npy_intp dims[2]{SIZE, SIZE};
const int ND = 2;
long double(*c_arr)[SIZE]{ new long double[SIZE][SIZE] };
for (int i = 0; i < SIZE; i++){
for (int j = 0; j < SIZE; j++){
c_arr[i][j] = i + j;}
}
// Convert it to a NumPy array.
PyObject *pArray = PyArray_SimpleNewFromData(ND, dims, NPY_LONGDOUBLE, reinterpret_cast<void*>(c_arr));
// import mymodule
const char *module_name = "mymodule";
PyObject *pName = PyUnicode_FromString(module_name);
PyObject *pModule = PyImport_Import(pName);
Py_DECREF(pName);
// import function
const char *func_name = "array_tutorial";
PyObject *pFunc = PyObject_GetAttrString(pModule, func_name);
PyObject *pReturn = PyObject_CallFunctionObjArgs(pFunc, pArray, NULL);
PyArrayObject *np_ret = reinterpret_cast<PyArrayObject*>(pReturn);
// Convert back to C++ array and print.
int len = PyArray_SHAPE(np_ret)[0];
long double* c_out;
c_out = reinterpret_cast<long double*>(PyArray_DATA(np_ret));
std::cout << "Printing output array - C++" << std::endl;
for (int i = 0; i < len; i++){
std::cout << c_out[i] << ' ';
}
std::cout << std::endl << std::endl;
// import function without arguments
const char *func_name2 = "myfunction";
PyObject *pFunc2 = PyObject_GetAttrString(pModule, func_name2);
PyObject *pReturn2 = PyObject_CallFunctionObjArgs(pFunc2, NULL);
PyArrayObject *np_ret2 = reinterpret_cast<PyArrayObject*>(pReturn2);
// convert back to C++ array and print
int len2 = PyArray_SHAPE(np_ret2)[0];
long double* c_out2;
c_out2 = reinterpret_cast<long double*>(PyArray_DATA(np_ret2));
std::cout << "Printing output array 2 - C++" << std::endl;
for (int i = 0; i < len2; i++){
std::cout << c_out2[i] << ' ';
}
std::cout << std::endl << std::endl;
Py_Finalize();
return 0;
}
与接受的答案相比,我不得不添加
setenv("PYTHONPATH", ".", 0);
为了确保找到 python 脚本,我为没有输入参数的函数 "myfunction" 添加了第二个函数调用,并删除了一些错误处理。
我在 Ubuntu 16.10 并使用
g++ -Wall numpy_cpp.cpp -I/usr/include/python3.5m/ -lpython3.5m
编译和 link(除 import_array() 发出的一个警告外一切正常)。我的目标是 python 3.
运行 但是该程序给出以下控制台输出:
array_tutorial - python
[[ 0.0 1.0 2.0]
[ 1.0 2.0 3.0]
[ 2.0 3.0 4.0]]
Printing output array - C++
0 1 2
myfunction - python
[[1 2 3]
[1 2 3]
[1 2 3]]
Printing output array 2 - C++
nan nan nan
这是给我带来麻烦的最后一个输出,其中 python return 是在 python 脚本中设置的 numpy 数组的第一行。 从 python print 语句来看,numpy 数组似乎很好(不是 nan),但一旦它被引用到 C++ 中,事情就会发生变化。
如果我在 array_tutorial 函数中取消注释 return 语句上方的两行,我会得到与第一个函数调用相同(令人失望)的结果。
因此,我的问题是如何在 C++ 中获取正确的值而不让对象(可能)超出范围?
对于冗长的 post,我深表歉意,在此先感谢您的帮助!
编辑: 正如下面 lomereiter 所指出的,python 中的 numpy 数组应该在设置时牢记数据类型。 这解决了问题。 一个更好的 python 脚本输出接收数组的数据类型并指定声明数组的数据类型是:
import numpy
def array_tutorial(a):
print("array_tutorial - python")
print(a)
print(numpy.dtype(a[0,0]))
print("")
firstRow = a[0,:]
#beta = numpy.array([[10,20,30],[10,20,30],[10,20,30]],dtype=numpy.float128)
#firstRow = beta[0,:]
return firstRow
def myfunction():
beta = numpy.array([[1,2,3],[1,2,3],[1,2,3]],dtype=numpy.float128)
print("myfunction - python")
print(beta)
print("")
firstRow = beta[0,:]
return firstRow
在 Python 代码中创建数组时应指定 dtype。您在 C++ 代码中转换为 long double,而 dtype 被推断为 int64(在 64 位平台上)