コードは Python 2 ヘッダー構成でコンパイルされています。Python 3 ヘッダー構成でコンパイルする場合、はモジュールの初期化関数をではなくとしてboost/python/module_init.hpp
宣言します。Boost.Python とライブラリでビルドされたモジュールは同じヘッダー構成を使用する必要があるため、適切なヘッダー構成を確認し、Boost.Python のクリーン ビルドを実行することを強くお勧めします。embedded_hello
PyInit_embedded_hello
initembedded_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_wrap
Python ( ) に公開します。example.Spam
- 公開された Python クラス (
example.Spam
) の使用方法を示します。
example.Spam
Python ( ) 内の公開された 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