简体   繁体   English

在 C++ 中嵌入 python/numpy

[英]Embed python / numpy in C++

I am trying to use python 3 (with numpy) in my C++ application.我正在尝试在我的 C++ 应用程序中使用 python 3(带 numpy)。 This entails sending a C++ array to python, performing calculations and then retrieving the result in C++.这需要将 C++ 数组发送到 python,执行计算,然后在 C++ 中检索结果。 To do this I based myself on the code that was discussed here: https://codereview.stackexchange.com/questions/92266/sending-ac-array-to-python-numpy-and-back/92353#92353 and also here: Sending a C++ array to Python and back (Extending C++ with Numpy) .为此,我基于此处讨论的代码: https : //codereview.stackexchange.com/questions/92266/sending-ac-array-to-python-numpy-and-back/92353#92353以及这里: 将 C++ 数组发送到 Python 并返回(使用 Numpy 扩展 C++)

While the example from the code review post basically works I am having troubles with the return values when I modified the python and C++ script: when I am trying to return a variable that was created in python the result is a vector of nan instead of the intended computations.虽然代码审查帖子中的示例基本上有效,但我在修改 python 和 C++ 脚本时遇到了返回值的问题:当我尝试返回在 python 中创建的变量时,结果是一个向量 nan 而不是预期的计算。 My guess is that the object somehow goes out of scope but I can't fix this problem.我的猜测是该对象以某种方式超出了范围,但我无法解决此问题。

I use the following python script in a file called mymodule.py :我在名为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

My C++ code is in the file numpy_cpp.cpp which is a slightly changed and simplified version of the accepted answer to the code review post.我的 C++ 代码位于文件numpy_cpp.cpp 中,它是代码审查帖子的已接受答案的略微更改和简化版本。

#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;
}

Compared to the accepted answer I had to add与接受的答案相比,我不得不补充

setenv("PYTHONPATH", ".", 0);

to make sure the python script is found, I added the second function call for the function "myfunction" that has no input arguments and I removed some of the error handling.为了确保找到 python 脚本,我为没有输入参数的函数“myfunction”添加了第二个函数调用,并删除了一些错误处理。

I am on Ubuntu 16.10 and and use我在 Ubuntu 16.10 上并且使用

g++ -Wall numpy_cpp.cpp -I/usr/include/python3.5m/ -lpython3.5m  

to compile and link (which goes fine except for one warning by import_array()).编译和链接(除了 import_array() 发出的一个警告外,一切正常)。 I am targeting python 3.我的目标是 python 3。

Running the program however gives the following console output:但是,运行该程序会提供以下控制台输出:

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 

It is the last output that gives me trouble, where python returns the first row of an numpy array that was set up in the python script.这是给我带来麻烦的最后一个输出,其中 python 返回在 python 脚本中设置的 numpy 数组的第一行。 From the python print statements it seems that the numpy array is fine (not nan), but once it is referred to C++ things go sideways.从 python 打印语句看来,numpy 数组很好(不是 nan),但是一旦它被引用到 C++,事情就会横盘整理。

If I uncomment the two lines above the return statement in the array_tutorial function I get the same (disappointing) result for the first function call.如果我取消注释 array_tutorial 函数中 return 语句上方的两行,我会得到相同(令人失望)的第一个函数调用结果。

My question is therefore how to get the correct values in C++ without the objects going (presumably) out of scope?因此,我的问题是如何在 C++ 中获得正确的值而不会使对象(大概)超出范围?

I apologize for the lengthy post, and thank you in advance for any help!对于冗长的帖子,我深表歉意,并在此先感谢您的帮助!


EDIT: As pointed out by lomereiter below the numpy arrays in python should be set up keeping the data types in mind.编辑:正如 lomereiter 所指出的,python 中的 numpy 数组应该在设置时记住数据类型。 This solves the problem.这解决了问题。 A better python script that outputs the data type of the received array and specifies the data type of the declared array would be:输出接收到的数组的数据类型并指定声明数组的数据类型的更好的 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

You should specify dtype when you create the array in Python code.您应该在 Python 代码中创建数组时指定 dtype。 You are casting to long double in C++ code while the dtype is deduced to be int64 (on 64-bit platforms)您在 C++ 代码中转换为 long double,而 dtype 被推断为 int64(在 64 位平台上)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM