Python を埋め込む場合、Python または Boost.Python へのほとんどすべての呼び出しは、インタープリターが で初期化された後に発生する必要がありますPy_Initialize()
。などを使用して、初期化の前にインタープリターを呼び出そうとするとboost::python::exec()
、未定義の動作が発生します。
exec
これでクラッシュの原因が特定されますが、Python とモジュールを埋め込むという最終目標を達成し、埋め込みモジュールをインポートするための微妙な詳細がいくつかあります。
- モジュールをインポートするとき、Python は最初にモジュールが組み込みモジュールかどうかをチェックします。モジュールが組み込みモジュールでない場合、Python はモジュール名に基づいてライブラリをロードしようとし、ライブラリがモジュールを初期化する関数を提供することを期待します。が組み込まれているため、組み込みモジュールを検索するときに が見つけられる
test_module
ように、その初期化を明示的に追加する必要があります。import
import
ステートメントは関数を使用します__import__
。exec
この関数は、のグローバル内で使用できる必要があります。
これを実現する方法を示す完全な例を次に示します。
#include <boost/python.hpp>
float func(int a)
{
return a*a-0.5;
}
BOOST_PYTHON_MODULE(test_module)
{
using namespace boost::python;
def("func", func);
}
// Use macros to account for changes in Python 2 and 3:
// - Python's C API for embedding requires different naming conventions for
// module initialization functions.
// - The builtins module was renamed.
#if PY_VERSION_HEX >= 0x03000000
# define MODULE_INIT_FN(name) BOOST_PP_CAT(PyInit_, name)
# define PYTHON_BUILTINS "builtins"
#else
# define MODULE_INIT_FN(name) BOOST_PP_CAT(init, name)
# define PYTHON_BUILTINS "__builtin__"
#endif
int main()
{
// Add the test_module module to the list of built-in modules. This
// allows it to be imported with 'import test_module'.
PyImport_AppendInittab("test_module", &MODULE_INIT_FN(test_module));
Py_Initialize();
namespace python = boost::python;
try
{
// Create an empty dictionary that will function as a namespace.
python::dict ns;
// The 'import' statement depends on the __import__ function. Thus,
// to enable 'import' to function the context of 'exec', the builtins
// module needs to be within the namespace being used.
ns["__builtins__"] = python::import(PYTHON_BUILTINS);
// Execute code. Modifications to variables will be reflected in
// the ns.
python::exec("b = 5", ns);
std::cout << "b is " << python::extract<int>(ns["b"]) << std::endl;
// Execute code using the built-in test_module.
python::exec(
"import test_module\n"
"var = test_module.func(b)\n",
ns);
std::cout << "var is " << python::extract<float>(ns["var"]) << std::endl;
}
catch (python::error_already_set&)
{
PyErr_Print();
}
}
実行すると、その出力は次のようになります。
b is 5
var is 24.5