如何通过Boost Python向Python模块添加类并在eval中调用?
问题:Boost.Python中向eval环境添加C++类的报错解决
我已经实现了向Python模块添加简单C函数并通过eval()调用的功能,但尝试添加C类时,执行boost::python::exec("import hello")或后续eval语句都会触发python::throw_error_already_set()异常,求正确的实现方式。
成功添加函数的示例代码
#include <boost/python.hpp> static int myFunc() { return 3; } int main() { auto main_module = boost::python::import("__main__"); auto main_namespace = main_module.attr("__dict__"); main_namespace["myFunc"] = boost::python::object(&myFunc); auto evalResult = boost::python::eval("myFunc()", main_namespace); assert((int)boost::python::extract<int>(evalResult) == 3); }
尝试添加类的报错代码
#include <boost/python.hpp> struct World { int myFunc() { return 3; } }; BOOST_PYTHON_MODULE(hello) { boost::python::class_<World>("World").def("myFunc", &World::myFunc); } int main() { auto main_module = boost::python::import("__main__"); auto main_namespace = main_module.attr("__dict__"); boost::python::exec("import hello"); auto evalResult = boost::python::eval("hello.World().myFunc()", main_namespace); assert((int)boost::python::extract<int>(evalResult) == 3); }
问题原因及解决方法
原因
用BOOST_PYTHON_MODULE定义的模块默认是作为动态库加载的,直接在宿主程序里执行import hello会找不到这个模块——因为模块没有被注册到Python解释器中,也没有对应的动态库文件。
解决方法
有两种可行的实现方式:
方式1:直接将类注册到当前命名空间
不需要定义独立的BOOST_PYTHON_MODULE,直接在main函数里把C++类注册到main_namespace中,操作逻辑和添加普通函数一致:
#include <boost/python.hpp> struct World { int myFunc() { return 3; } }; int main() { auto main_module = boost::python::import("__main__"); auto main_namespace = main_module.attr("__dict__"); // 直接将World类注册到当前命名空间 boost::python::class_<World>("World").def("myFunc", &World::myFunc); // 也可以显式绑定到main_namespace // main_namespace["World"] = boost::python::class_<World>("World").def("myFunc", &World::myFunc); auto evalResult = boost::python::eval("World().myFunc()", main_namespace); assert((int)boost::python::extract<int>(evalResult) == 3); }
方式2:手动注册模块到Python解释器
如果一定要保留BOOST_PYTHON_MODULE的模块定义,可以在main函数中手动调用模块的初始化函数,将模块注册到Python解释器中:
#include <boost/python.hpp> struct World { int myFunc() { return 3; } }; BOOST_PYTHON_MODULE(hello) { boost::python::class_<World>("World").def("myFunc", &World::myFunc); } int main() { Py_Initialize(); // 确保Python解释器完成初始化 auto main_module = boost::python::import("__main__"); auto main_namespace = main_module.attr("__dict__"); // 手动调用模块初始化函数,注册hello模块 inithello(); // 函数名对应BOOST_PYTHON_MODULE(hello)生成的初始化入口 auto evalResult = boost::python::eval("hello.World().myFunc()", main_namespace); assert((int)boost::python::extract<int>(evalResult) == 3); Py_Finalize(); }
注意:这种方式下,编译时需要确保链接器能找到inithello()函数,部分编译器可能需要显式导出该函数。
内容的提问来源于stack exchange,提问作者Lacer
相关产品推荐
相关产品推荐

