web-dev-qa-db-ja.com

C ++オブジェクトをPythonに渡す

この質問は、(C++)組み込みpythonインタープリターで呼び出されるPython関数にC++オブジェクトを渡す方法についてです

次の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

C++クラスを公開するpythonモジュールは、次のSwigインターフェイスファイルによって生成できます。

%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()

この質問は、C++オブジェクトを引数として使用して、c ++から呼び出されたときにpythonexecute()関数が機能するようにする方法に関するものです。

次の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 function)が表示されているため、渡されたオブジェクトがそうでないことを示していますindeed、有効なMyClassオブジェクト。

Int、double、string型などの単純型をC/C++からPythonに渡す方法の例はたくさんあります。しかし、C/C++オブジェクト/ポインターを渡す方法を示す例はほとんどありません。

CMakeファイルを使用した上記のコードは、githubからチェックアウトできます。 https://github.com/TotteKarlsson/miniprojects/tree/master/passMeToPython

このコードは、ブーストpythonまたは他のAPIを使用するものではありません。ただし、Cythonはおもしろそうに聞こえます。Cythonを使用してC++側で単純化できる場合は、受け入れ可能です。

28
Totte Karlsson

これは私自身の質問に対する部分的な答えです。より良い方法があると信じているので、私は部分的に言っています。

この投稿に基づいて 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関数の引数として使用すると、上記のコードのpythonexecute()関数正常に実行され、Pythonコード、生成されたpythonモジュールを使用して、MyClassオブジェクトの内部データに適切にアクセスできます。これは素晴らしいです。

上記のコードは、C++とPythonの間でデータを渡す方法、および取得する方法を非常に単純な方法で示していますが、理想的ではありません。

C++コードでのswigヘッダーファイルの使用法は、実際にはそれほどきれいではありません。さらに、「_ p_MyClass」コードを見つけるには、ユーザーがswigで生成されたラッパーコードを「手動で」調べる必要があります。

もっと良い方法があるはず!?これをもっと見栄えよくするために、swigインターフェースファイルに何か追加する必要があるでしょうか?

8
Totte Karlsson