如何将 3D Python 列表传递给 C++ 程序

Posted

技术标签:

【中文标题】如何将 3D Python 列表传递给 C++ 程序【英文标题】:How can I pass a 3D Python list to a c++ program 【发布时间】:2021-07-29 14:16:18 【问题描述】:

我有一个 .py 文件,其中包含签名浮点数的 3d 列表。

test.py

def myfunc():
    tabToReturn = [[[-1.03,5.68],[4.16,-78.12]],[[74.1,8.95],[59.82,1.48]],[[74.1,8.95],[59.82,87.4]]]
    print(tabToReturn)
    return tabToReturn

我想调用那个 .py,让它返回这个 3d 列表,并将它转换为我的 c++ 程序的 3D 矢量。

这是一个检查我是否得到我们需要的示例:

program.cpp

#include <iostream>
std::vector<std::vector<std::vector<float>>> callPython();
int main(int argc, char** argv)



    std::vector<std::vector<std::vector<float>>> my3DVector = callPython();
    

    std::cout << "Result we got : "<< std::endl;

    for (int i = 0; i < my3DVector.size(); i++)
    


        for (int j = 0; j < my3DVector[i].size(); j++)
        

            for (int k = 0; k < my3DVector[i][j].size(); k++)
            
                std::cout << my3DVector[i][j][k];
                std::cout << " ";

            


        
        std::cout << "" << std::endl;
    

输出应该是:

Result we got :
-1.03 5.68
4.16 -78.12
74.1 8.95
59.82 1.48
74.1 8.95
59.82 87.4

我已经看到了一些关于这个主题的问题,here 和 here

问题是其中一个问题有一个我完全看不懂的答案,而第二个只是关于返回的浮点数,我需要一个3D矢量,我在这里没有找到我需要的东西

另外,这个tutorial 没有解释如何传递一个 3d 列表,甚至根本没有一个列表。

【问题讨论】:

是否允许作弊并将 Python 数组输出视为 JSON? @Botje 是的,我可以做任何事情。但如果可能的话,最好避免这种情况,因为我对 JSON 一无所知。 有点hacky,但你可以将脚本输出到文件中,然后C++可以读取文件并从中创建向量。一行将是您的一对数字中的一个。或者您可以输出某种格式(提到了 JSON,但也可以使用其他格式)。 【参考方案1】:

在 Python 方面:

json.dump(mylist, fp=open("out.json", "w"))

在 C++ 方面,使用 nlohmann::json,一个仅头文件的库:

system("python mypyfile.py");

using nlohmann::json;
std::ifstream jsonfile("out.json");
json mylist;
jsonfile >> mylist;

std::vector<std::vector<std::vector<float>>> matrix;
for (auto& dim1: mylist) 
  std::vector<std::vector<float>> dim1v;
  for (auto& dim2: dim1) 
    std::vector<float> dim2v;
    for (auto& elem: dim2) 
      dim2v.push_back(elem.get<float>());
    
    dim1v.push_back(dim2v);
  
  matrix.push_back(dim1v);

【讨论】:

【参考方案2】:
#creating 3d list

3D_list= [[ [A,B], [C,D] ] ,[ [E,F], [G,H] ], [ [I,J],[K,L] ] ]

#printing 3d list

print(3D_list)

【讨论】:

【参考方案3】:

尽管@Botje 的回答(可能)是正确的,但我得到了一个不使用 json 的解决方案。

经过一番挣扎,我找到了C-API的来源:

多亏了我找到了解决这个问题的解决方案,无论你的向量的维度是多少。

详情如下:

#include <Python.h> //first to import
#include <iostream>
std::vector<std::vector<std::vector<float>>> callPython()

    std::cout << "Initialize the library" << std::endl;
    Py_Initialize();

    std::cout << "I get the python file name" << std::endl;
    PyObject* pyFile = PyUnicode_FromString((char*)"test");


    std::cout << "I import it" << std::endl;
    PyObject* myModule = PyImport_Import(pyFile);

    auto mdict = PyModule_GetDict(myModule);



    std::cout << "I get the name of the function I want to use from my python file" << std::endl;
    PyObject* myFunction = PyDict_GetItemString(mdict, "myfunc");


    std::cout << "I create the parameter I need to use" << std::endl;
    
    
    std::cout << "INFO : According to the API, we do not use PyString_ since Python 3.X anymore, but PyBytes" << std::endl;
    //----
    std::cout << "We call the function (with the appropriate parameter), we have imported and store the result in my result" << std::endl;
    auto myResult = PyObject_CallFunction(myFunction, NULL);

    if (!PyList_Check(myResult))
    
        std::cout << "(!) (!) (!) THAT IS NOT A LIST (!) (!) (!)" << std::endl;
    


    //----Getting the element givent by the python program, and store them in a 3d vector

    std::cout << "We iterate through the list stored in myResult and store everything in a 3D vector" << std::endl;
    //--the 3d vector we need, you must change its dimension if you work with different dimensions
    std::vector<std::vector<std::vector<float>>> my3DVector;
    //--each list in another list is a Python Object that we should extract
    
for (Py_ssize_t i = 0; i < PyList_Size(myResult); i++)

    PyObject* firstDim = PyList_GetItem(myResult, i);

    std::vector<std::vector<float>> secondDimCpp; 

    for (Py_ssize_t j = 0; j < PyList_Size(firstDim); j++)
    
        PyObject* secondDim = PyList_GetItem(firstDim, j);

        std::vector<float> lastDimCpp; 


        for (Py_ssize_t k = 0; k < PyList_Size(secondDim); k++)
        
            PyObject* thirdDim = PyList_GetItem(secondDim, k); //we get the value of an axis

            float value = PyFloat_AsDouble(thirdDim); //we convert it to a double

            lastDimCpp.push_back(value); //we store it in a vector

        

        secondDimCpp.push_back(lastDimCpp);
    
    my3DVector->push_back(secondDimCpp);




    return my3DVector;

注意:我这里是按值返回向量,效率不高,你可能更喜欢用智能指针返回

另外,由于这是一个多维列表,我们必须使用ListObjects

【讨论】:

以上是关于如何将 3D Python 列表传递给 C++ 程序的主要内容,如果未能解决你的问题,请参考以下文章

将 C# 3D 数组作为 1D 字节数组传递给 C++ 库

在 C++ 中嵌入 Python。传递接收列表列表的字符串向量

如何传递python列表地址

SWIG:如何将复数向量从 C++ 传递到 python

如何在pybind11中将共享指针列表传递给c++对象

如何通过 cython 将 numpy 数组列表传递给 c++