我将Python(使用boost :: python)嵌入到使用回调的应用程序插件中。基本上,我想做一些事情:
在Python中(比如test.py):
def do_something():
...
register_callback(do_something)
在C ++方面,我注册了register_callback()函数:
void register_callback(boost::python::object& o)
{
// Access some persistent state information
}
BOOST_PYTHON_MODULE(foo)
{
boost::python::def("register_callback", register_callback);
}
void library_entry()
{
PyImport_AppendInittab("foo", initfoo);
PyInitialize();
// Create some persistent state information
boost::python::exec_file("test.py", ...);
}
这里的问题是我需要创建Python上下文并将内容存储在一个不透明的指针中,然后返回给应用程序。当Python回调C ++时,我需要恢复那个不透明的值。例如:
申请 - (电话) - >我的C ++库 - (运行) - > Python脚本 - (调用) - >我的C ++库
对于最后一步,我需要恢复一些不透明的数据。此外,我需要持久的不透明数据。对我的C ++库的调用是来自应用程序的回调。我遇到的问题是试图弄清楚如何将该状态信息传递给C ++ register_callback()函数。我尝试过类似的东西:
namespace bp = boost::python;
class state_info_t
{
};
void register_callback(std::shared_ptr<state_info_t>& state, bp::object& o);
{
// Access some persistent state information
}
// Create some persistent state information
std::shared_ptr<state_info_t> state = std::make_shared<state_info_t>();
PyImport_AppendInittab("foo", initfoo);
Py_Initialize();
std::shared_ptr<bp::object> main_module = std::make_shared<bp::object>(bp::handle<>(bp::borrowed(PyImport_AddModule("__main__"))));
bp::object main_namespace = main_module->attr("__dict__");
std::shared_ptr<bp::object> foo_module = std::make_shared<bp::object>(bp::handle<>(PyImport_ImportModule("foo")));
main_namespace["foo"] = *foo_module;
bp::scope foo_scope(*foo_module);
// Both of these fail with _a lot_ of errors, most related to "no matching function call to 'get_signature'
bp::def("register_callback",
[&](bp::object& o) { register_callback(state, o); },
bp::arg("func"));
bp::def("register_callback",
std::bind(register_callback, state, std::placeholders::_1),
bp::arg("func"));
我的另一个想法是将持久性数据存储在模块的字典中。但我不知道如何在回调中恢复它。例如:
// Create some persistent state information
std::shared_ptr<state_info_t> state = std::make_shared<state_info_t>();
PyImport_AppendInittab("foo", initfoo);
Py_Initialize();
std::shared_ptr<bp::object> main_module = std::make_shared<bp::object>(bp::handle<>(bp::borrowed(PyImport_AddModule("__main__"))));
bp::object main_namespace = main_module->attr("__dict__");
std::shared_ptr<bp::object> foo_module = std::make_shared<bp::object>(bp::handle<>(PyImport_ImportModule("foo")));
bp::object foo_namespace = main_module->attr("__dict__");
main_namespace["foo"] = *foo_module;
foo_namespace["state"] = bp::handle<>(state); // Whatever the appropriate wrapper is
然后在register_callback的C ++端:
void register_callback(bp::object& o)
{
// How do I extract "state" from the context?
}
我并不热衷于最后一个,因为它将状态信息暴露给脚本。
我不想让状态信息全局化,因为可能有多个正在运行的Python实例。无论如何,对于多个Python实例,我仍然需要一种方法来确定正在运行哪个Python实例来选择适当的状态信息。
答案 0 :(得分:0)
我想我找到了一种方法来实现我想要的目标。
我可以创建一个类,然后将该类的实例放入sys.modules中,而不是实际创建一个模块(参见this answer)。
所以我这样做:
namespace bp = boost::python;
class foo
{
public:
void register_callback(bp::object&);
};
...
// Register foo with Python (in the current scope)
bp::object foo_class = bp::class_<foo>("foo")
.def("register_callback", &foo::register_callback);
// Get sys.modules
bp::object obj(bp::handle<>(bp::borrowed(PyImport_GetModuleDict())));
// Add an instance of foo to sys.modules
obj["foo"] = foo_class();
现在,在python中:
import foo
def func():
...
foo.register_callback(func)
这似乎使类实例显示为模块,并作为模块工作。