在PyBind11中从C++调用Python类方法

qltillow  于 2024-01-09  发布在  Python
关注(0)|答案(1)|浏览(240)

考虑Python中的回调类。

  1. class My_Callback():
  2. def __init__(self):
  3. pass
  4. def do_something(self, something):
  5. print(something)

字符串
这个类在一个DLL Package 器中使用,该 Package 器使用pybind11将其暴露给python。对这个类的引用存储在一个ENUM中,并传递给一个C++函数。

  1. void callPy(py::object f) {
  2. //call f.do_something("test");
  3. }
  4. // ...
  5. callPy(userData::myCallback);


有很多关于如何从C++(pybind11 doc)调用Python函数的例子,但是调用类方法的方式是什么呢?感觉好像我应该将py::object转换为My_Callback,但我不知道如何做到这一点。
下面的代码行似乎可以完成这项工作,但这真的是预期的方法吗?

  1. void callPy(py::object f) {
  2. py::object mycallback = f.attr("do_something");
  3. mycallback("test");
  4. }

ikfrs5lh

ikfrs5lh1#

你可以使用attr方法调用一个Python类的绑定函数来获取函数对象,然后以类似于std::function的方式调用它。

  1. py::detail::str_attr_accessor do_something_func = my_callback.attr("do_something");
  2. do_something_func("test");

字符串
在pybind 11的最新主分支中,他们添加了额外的类型化对象,如果你想更明确地表达你所期望的类型,你可以将str_attr_accessor转换为。

  1. auto do_something_func = my_callback.attr("do_something").cast<py::typing::Callable<void(std::string)>>();
  2. do_something_func("test");


如果你想让函数只接受My_Callback类型的对象,并且生成的类型traits是正确的,你必须创建一个py::object的自定义实现来检查My_Callback示例。这个方法还允许你添加一个自定义c++方法来处理do_something属性转换和调用。

  1. PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
  2. // create custom type object for more explicit type hints generated (My_Callback instead of Any)
  3. struct My_Callback : py::object
  4. {
  5. using py::object::object;
  6. static bool check_(handle h)
  7. {
  8. // this is probably not the best way to handle this, but I wanted to avoid string comparison
  9. // static so we only invoke once
  10. static py::type my_callback_type = py::module_::import("__main__").attr("My_Callback").cast<py::type>();
  11. return isinstance(h, my_callback_type);
  12. }
  13. void do_something(std::string&& something)
  14. {
  15. attr("do_something")(something);
  16. }
  17. };
  18. PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
  19. void callPy(py::My_Callback& my_callback)
  20. {
  21. my_callback.do_something("test");
  22. }
  23. PYBIND11_MODULE(pybind11_example, m)
  24. {
  25. m.def("call_py", &callPy, "my_callback"_a);
  26. }


这也生成了一个更好的帮助文档的功能
关于模块pybind11_example的帮助:
名称pybind11_example
FUNCTIONS内置函数的call_py(...)方法。PyCapsule示例call_py(my_callback:My_Callback)->无
pybind11_loggen也会生成这个

  1. from __future__ import annotations
  2. __all__ = ['call_py']
  3. def call_py(my_callback: My_Callback) -> None:
  4. ...

展开查看全部

相关问题