簡體   English   中英

從Python向C ++回調傳遞不透明數據

[英]Passing opaque data to C++ callback from Python

我將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實例以選擇適當的狀態信息。

我想我找到了實現自己想要的方法。

我可以創建一個類,而不是實際創建模塊,然后將該類的實例放入sys.modules中(請參閱此答案 )。

所以我做這樣的事情:

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)

這似乎使類實例作為模塊出現,並作為模塊工作。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM