簡體   English   中英

在 C++ 中嵌入 python/numpy

[英]Embed python / numpy in C++

我正在嘗試在我的 C++ 應用程序中使用 python 3(帶 numpy)。 這需要將 C++ 數組發送到 python,執行計算,然后在 C++ 中檢索結果。 為此,我基於此處討論的代碼: https : //codereview.stackexchange.com/questions/92266/sending-ac-array-to-python-numpy-and-back/92353#92353以及這里: 將 C++ 數組發送到 Python 並返回(使用 Numpy 擴展 C++)

雖然代碼審查帖子中的示例基本上有效,但我在修改 python 和 C++ 腳本時遇到了返回值的問題:當我嘗試返回在 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 中,它是代碼審查帖子的已接受答案的略微更改和簡化版本。

#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  

編譯和鏈接(除了 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 返回在 python 腳本中設置的 numpy 數組的第一行。 從 python 打印語句看來,numpy 數組很好(不是 nan),但是一旦它被引用到 C++,事情就會橫盤整理。

如果我取消注釋 array_tutorial 函數中 return 語句上方的兩行,我會得到相同(令人失望)的第一個函數調用結果。

因此,我的問題是如何在 C++ 中獲得正確的值而不會使對象(大概)超出范圍?

對於冗長的帖子,我深表歉意,並在此先感謝您的幫助!


編輯:正如 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 位平台上)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM