14

C++ プロジェクトに取り組んでいるときに、自分の本業ではないサード パーティのライブラリを探していました。必要なことを正確に実行する、非常に優れたライブラリを見つけましたが、それは Python で書かれています。Boost.Python ライブラリを使用して、Python コードを C++ に埋め込む実験を行うことにしました。

C++ コードは次のようになります。

#include <string>
#include <iostream>
#include <boost/python.hpp>

using namespace boost::python;

int main(int, char **) 
{
    Py_Initialize();

    try 
    {
        object module((handle<>(borrowed(PyImport_AddModule("__main__")))));

        object name_space = module.attr("__dict__");
        object ignored = exec("from myModule import MyFunc\n"
                          "MyFunc(\"some_arg\")\n",
                          name_space);

        std::string res = extract<std::string>(name_space["result"]);
    } 
    catch (error_already_set) 
    {
        PyErr_Print();
    }

    Py_Finalize();
    return 0;
}

Python コードの (非常に) 単純化されたバージョンは次のようになります。

import thirdparty

def MyFunc(some_arg):
    result = thirdparty.go()
    print result

問題は次のとおりです。「MyFunc」は正常に実行され、「結果」の出力が表示されます。私ができないことは、C++ コードから「結果」を読み取ることです。抽出コマンドは、どの名前空間でも「結果」を見つけることはありません。「結果」をグローバルとして定義しようとしましたが、タプルを返そうとしましたが、動作させることができません。

4

4 に答える 4

9

まず、関数をreturn値に変更します。print値を取り戻したいので、それを行うと事態は複雑になります。あなたMyModule.pyがこのように見えるとしましょう:

import thirdparty

def MyFunc(some_arg):
    result = thirdparty.go()
    return result

今、あなたが望むことをするために、あなたはドキュメンテーションが言うように、基本的な埋め込みを超えなければなりません。関数を実行するための完全なコードは次のとおりです。

#include <Python.h>

int
main(int argc, char *argv[])
{
    PyObject *pName, *pModule, *pFunc;
    PyObject *pArgs, *pArg, *pResult;
    int i;

    Py_Initialize();
    pName = PyString_FromString("MyModule.py");
    /* Error checking of pName left out as exercise */

    pModule = PyImport_Import(pName);
    Py_DECREF(pName);

    if (pModule != NULL) {
        pFunc = PyObject_GetAttrString(pModule, "MyFunc");
        /* pFunc is a new reference */

        if (pFunc) {
            pArgs = PyTuple_New(0);
            pArg = PyString_FromString("some parameter")
            /* pArg reference stolen here: */
            PyTuple_SetItem(pArgs, 0, pArg);
            pResult = PyObject_CallObject(pFunc, pArgs);
            Py_DECREF(pArgs);
            if (pResult != NULL) {
                printf("Result of call: %s\n", PyString_AsString(pResult));
                Py_DECREF(pResult);
            }
            else {
                Py_DECREF(pFunc);
                Py_DECREF(pModule);
                PyErr_Print();
                fprintf(stderr,"Call failed\n");
                return 1;
            }
        }
        else {
            if (PyErr_Occurred())
                PyErr_Print();
            fprintf(stderr, "Cannot find function");
        }
        Py_XDECREF(pFunc);
        Py_DECREF(pModule);
    }
    else {
        PyErr_Print();
        fprintf(stderr, "Failed to load module");
        return 1;
    }
    Py_Finalize();
    return 0;
}
于 2008-10-19T01:53:32.397 に答える
4

ΤΖΩΤΖΙΟΥ、Josh、および Nosklo の回答に基づいて、boost.python を使用して最終的に機能するようになりました。

パイソン:

import thirdparty

def MyFunc(some_arg):
    result = thirdparty.go()
    return result

C++:

#include <string>
#include <iostream>
#include <boost/python.hpp>

using namespace boost::python;

int main(int, char **) 
{
    Py_Initialize();

    try 
    {
        object module = import("__main__");
        object name_space = module.attr("__dict__");
        exec_file("MyModule.py", name_space, name_space);

        object MyFunc = name_space["MyFunc"];
        object result = MyFunc("some_args");

        // result is a dictionary
        std::string val = extract<std::string>(result["val"]);
    } 
    catch (error_already_set) 
    {
        PyErr_Print();
    }

    Py_Finalize();
    return 0;
}

いくつかの重要なポイント:

  1. 便宜上、「exec」を「exec_file」に変更しました。プレーンな「exec」でも動作します。
  2. 失敗した主な理由は、「ローカル」name_sapce を「exec」または「exec_file」に渡さなかったことです。これは、name_space を 2 回渡すことで修正されました。
  3. Python 関数が Unicode 文字列を返す場合、それらは「std::string」に変換できないため、すべての Python 文字列の末尾に「.encode('ASCII', 'ignore')」を付ける必要がありました。
于 2008-10-19T09:47:47.557 に答える
1

PyObject_CallObject(<py function>, <args>)必要なのは、PyObjectとして呼び出す関数の戻り値を返すか、PyRun_String(<expression>, Py_eval_input, <globals>, <locals>)単一の式を評価してその結果を返すかのいずれかだと思います。

于 2008-10-19T01:20:35.460 に答える
0

MyFunc から結果を返すことができるはずです。結果は、現在「無視」されている変数に格納されます。これにより、他の方法でアクセスする必要がなくなります。

于 2008-10-19T00:19:55.377 に答える