簡體   English   中英

將 C++ 對象傳遞給 Python

[英]Passing a C++ object to Python

這個問題是關於如何將 C++ 對象傳遞給在 (C++) 嵌入式 Python 解釋器中調用的 python 函數

以下 C++ 類 (MyClass.h) 設計用於測試:

#ifndef MyClassH
#define MyClassH
#include <string>

using std::string;
class MyClass
{
    public:
                        MyClass(const string& lbl): label(lbl) {}
                        ~MyClass(){}
        string          getLabel() {return label;}

    private:
        string          label;
};
#endif

可以通過以下 Swig 接口文件生成一個暴露 C++ 類的 python 模塊:

%module passmetopython

%{    #include "MyClass.h"    %}

%include "std_string.i"

//Expose to Python
%include "MyClass.h"

下面是一個使用 python 模塊的 Python 腳本

import passmetopython as pmtp

def execute(obj):
    #This function is to be called from C/C++, with a
    #MyClass object as an argument
    print ("Entering execute function")
    lbl = obj.getLabel();
    print ("Printing from within python execute function. Object label is: " + lbl)
    return True

def main():
    c = pmtp.MyClass("Test 1")
    retValue = execute(c)
    print("Return value: " + str(retValue))

#Test function from within python
if __name__ == '__main__':
    main()

這個問題是關於如何讓 python execute()函數在從 C++ 調用時以 C++ 對象作為參數工作。

編寫了以下 C++ 程序來測試函數(最少的錯誤檢查):

#include "Python.h"
#include <iostream>
#include <sstream>
#include "MyClass.h"

using namespace std;

int main()
{
    MyClass obj("In C++");
    cout << "Object label: \"" << obj.getLabel() << "\"" << endl;

    //Setup the Python interpreter and eventually call the execute function in the
    //demo python script
    Py_Initialize();

    //Load python Demo script, "passmetopythonDemo.py"
    string PyModule("passmetopythonDemo");
    PyObject* pm = PyUnicode_DecodeFSDefault(PyModule.c_str());

    PyRun_SimpleString("import sys");
    stringstream cmd;
    cmd << "sys.path.append(\"" << "." << "\")";
    PyRun_SimpleString(cmd.str().c_str());
    PyObject* PyModuleP = PyImport_Import(pm);
    Py_DECREF(pm);

    //Now create PyObjects for the Python functions that we want to call
    PyObject* pFunc = PyObject_GetAttrString(PyModuleP, "execute");

    if(pFunc)
    {
        //Setup argument
        PyObject* pArgs = PyTuple_New(1);

        //Construct a PyObject* from long
        PyObject* pObj(NULL);

        /* My current attempt to create avalid argument to Python */
        pObj = PyLong_FromLong((long) &obj);


        PyTuple_SetItem(pArgs, 0, pObj);

        /***** Calling python here *****/
        cout<<endl<<"Calling function with an MyClass argument\n\n";
        PyObject* res = PyObject_CallObject(pFunc, pArgs);
        if(!res)
        {
            cerr << "Failed calling function..";
        }
    }

    return 0;
}

運行上述代碼時,以 MyClass 對象作為參數的execute() python 函數失敗並返回 NULL。 但是,進入了Python函數,因為我可以看到控制台輸出中的輸出( Entering execute function ),表明傳遞的對象確實不是有效的MyClass對象。

有很多關於如何從 C/C++ 向 Python 傳遞簡單類型(如整數、雙精度或字符串類型)的示例。 但是很少有例子展示如何傳遞C/C++對象/指針,這有點令人費解。

上面的代碼,帶有一個CMake文件,可以從github上檢出: https : //github.com/TotteKarlsson/miniprojects/tree/master/passMeToPython

此代碼不使用任何 boost python 或其他 API。 Cython 聽起來很有趣,如果它可以用於簡化 C++ 方面,它可能是可以接受的。

這是對我自己的問題的部分回答。 我說部分,因為我相信有更好的方法。

基於這篇文章http://swig.10945.n7.nabble.com/Pass-a-Swig-wrapped-C-class-to-embedded-Python-code-td8812.html我生成了 swig 運行時標頭,如上所述此處,第 15.4 節: http : //www.swig.org/Doc2.0/Modules.html#Modules_external_run_time

在上面的 C++ 代碼中包含生成的頭文件,允許編寫以下代碼:

    PyObject* pObj = SWIG_NewPointerObj((void*)&obj, SWIG_TypeQuery("_p_MyClass"),  0 ); 

此代碼使用來自 Swig python 包裝源文件的信息,即 MyClass 類型的“swig”名稱,即_p_MyClass

使用上面的 PyObject* 作為 PyObject_CallObject 函數的參數,上面代碼中的 python execute()函數執行得很好,並且使用生成的 python 模塊的 Python 代碼確實可以正確訪問 MyClass 對象的內部數據。 這很棒。

雖然上面的代碼以一種非常簡單的方式說明了如何在 C++ 和 Python 之間傳遞和檢索數據,但在我看來它並不理想。

C++ 代碼中 swig 頭文件的使用確實不是那么漂亮,此外,它需要用戶“手動”查看 swig 生成的包裝代碼以找到“_p_MyClass”代碼。

一定會有更好的辦法!? 也許應該在 swig 接口文件中添加一些東西以使它看起來更好?

不幸的是,它在我的情況下不起作用。 我在SWIG_TypeQuery("_p_MyClass")宏中得到 nullptr 異常。

您能否分享更多詳細信息如何進行此類傳遞?

  1. 我有 MyClass 庫
  2. 基於這個庫,我使用 swig 創建了模塊
  3. 接下來我使用 -external-runtime 創建了 swigpyrun.h 文件
  4. 我將此文件包含在我的 main.cpp 中,並且 SWIG_TypeQuery("_p_MyClass") 給出了一個錯誤

我什至嘗試添加像 SWIG_TYPE_TABLE 這樣的定義,但沒有幫助。

順便說一句,我正在使用 MSVS 編譯器

PyObject *pValue;
pValue = PyObject_CallMethod(pInstance, "add","(i)",x);
if (pValue)
    Py_DECREF(pValue);
else
    PyErr_Print();

暫無
暫無

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

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