6

次の Boost.Python v1.56 の例は、Python 3.4.2 インタープリターを独自のアプリケーションに埋め込む方法を示しています。残念ながら、この例は、Windows 8.1 で MSVC2013 を使用した私の構成ではそのままでは機能しません。また、埋め込みに関する完全に機能する例は 1 つも見つかりませんでした。少なくとも 10 年ほど前のものはありません。

実行すると次のエラーが表示されます: ImportError: 'embedded_hello' is not a built-in module

コードはこちら: http://pastebin.com/shTtdxT8

これを実行するために何ができるかについてのヒントはありますか? 一般的に、Python で C++ クラスを公開する方法、およびその逆の方法は?

4

1 に答える 1

11

コードは Python 2 ヘッダー構成でコンパイルされています。Python 3 ヘッダー構成でコンパイルする場合、はモジュールの初期化関数をではなくとしてboost/python/module_init.hpp宣言します。Boost.Python とライブラリでビルドされたモジュールは同じヘッダー構成を使用する必要があるため、適切なヘッダー構成を確認し、Boost.Python のクリーン ビルドを実行することを強くお勧めします。embedded_helloPyInit_embedded_helloinitembedded_hello

さらに、組み込みテーブルにモジュールを追加する場合、PyImport_AppendInittab()呼び出しは の前に発生する必要がありますPy_Initialize()PyImport_AppendInittab()ドキュメントには明示的に次のように記載されています。

組み込みモジュールの既存のテーブルに単一のモジュールを追加します。... これは の前に呼び出す必要がありますPy_Initialize()

Boost.Python は、BOOST_PYTHON_MODULEマクロを使用して Python モジュールを定義します。モジュールの本体内では、現在のスコープはモジュール自体です。したがって、C++ クラスが を介して Python に公開される場合など、C++ 型が型ラッパーを介して公開される場合boost::python::class_、結果の Python クラスは で定義されたモジュール内に配置されBOOST_PYTHON_MODULEます。

一方、Python で宣言されたユーザー定義型はファーストクラスのオブジェクトです。C++ の観点からは、それらはファクトリ関数であるかのように扱うことができます。したがって、Python で定義されたクラスを C++ で使用するには、クラス オブジェクトへのハンドルを取得し、クラス オブジェクトを呼び出してクラスのインスタンスをインスタンス化する必要があります。


以下は、Python 3 インタープリターの埋め込みを示す完全な最小限の例です。

  • exampleバイナリに直接ビルドされたモジュール ( ) をインポートし、基本的な C++ クラス ( ) をデフォルトで仮想関数/ディスパッチを持つspam_wrapPython ( ) に公開します。example.Spam
  • 公開された Python クラス ( example.Spam) の使用方法を示します。
  • example.SpamPython ( ) 内の公開された Python クラス ( ) から派生しexample.PySpam、結果のクラスを使用します。
#include <iostream>
#include <boost/python.hpp>

/// @brief Mockup Spam model.
struct spam
  : boost::noncopyable
{
  virtual ~spam() {};
  virtual std::string hello() { return "Hello from C++"; }
};

//@ brief Mockup Spam wrapper.
struct spam_wrap
  : spam,
    boost::python::wrapper<spam>
{
  virtual std::string hello()
  {
#if BOOST_WORKAROUND(BOOST_MSVC, <= 1300)
    return boost::python::call<std::string>(
      this->get_override("hello").ptr());
#else
    return this->get_override("hello")();
#endif
  }

  std::string default_hello() { return this->spam::hello(); }
};

/// @brief Python example module.
BOOST_PYTHON_MODULE(example)
{
  namespace python = boost::python;

  // Expose C++ spam_wrap as Python Spam class.
  python::class_<spam_wrap, boost::noncopyable>("Spam")
    .def("hello", &spam::hello, &spam_wrap::default_hello)
    ;
}   

int main()
{
  // Add example to built-in.
  PyImport_AppendInittab("example", &PyInit_example);

  // Start the interpreter.
  Py_Initialize();

  namespace python = boost::python;
  try
  {
    python::object main = python::import("__main__");
    python::object global = main.attr("__dict__");

    // Execute Python code, using the example module.
    exec(
      "from example import Spam          \n"
      "spam = Spam()                     \n"
      "                                  \n"
      "class PySpam(Spam):               \n"
      "    def hello(self):              \n"
      "        return 'Hello from Python'\n",     
      global, global);

    /// Check the instance of the Python object using the C++ class.
    // >>> spam_object = spam
    python::object spam_object = global["spam"];
    assert(python::extract<spam>(spam_object).check());
    // >>> result = spam_object.hello()
    python::object result = spam_object.attr("hello")();
    // >>> print(result)
    std::cout << python::extract<std::string>(result)() << std::endl;
    // >>> assert("Hello from C++" == result)
    assert("Hello from C++" == python::extract<std::string>(result)());

    /// Create an instance using PySpam class.  It too is a Python object.
    // >>> py_spam_type = PySpam
    python::object py_spam_type = global["PySpam"];
    // >>> py_spam_object = py_spam_type()
    python::object py_spam_object = py_spam_type();
    // >>> result = py_spam_object()
    result = py_spam_object.attr("hello")();
    // >>> print(result)
    std::cout << python::extract<std::string>(result)() << std::endl;
    // >>> assert("Hello from Python" == result)
    assert("Hello from Python" == python::extract<std::string>(result)());
  }
  catch (const python::error_already_set&)
  {
    PyErr_Print();
  }
}

プログラムはエラーなしで完了するまで実行され、次の出力が得られます。

Hello from C++
Hello from Python
于 2014-11-07T05:47:42.763 に答える