如何从py::module对象访问已绑定的py::class类?
问题
在使用pybind11暴露C++代码时,能否从py::module对象访问已定义的py::class类?已知可以从绑定类直接使用attr,但想知道能否通过模块实现同样操作。
具体场景是实现MyOtherClass的__repr__方法时,调用已为MyClass定义的__repr__,现有代码如下:
#include <pybind11/pybind11.h> #include <pybind11/stl.h> #include <pybind11/operators.h> class MyClass { public: MyClass() = default; // ... }; class MyOtherClass { public: MyOtherClass() = default; // ... MyClass val; }; // ------------------------------------------------------------------------- template < typename T > py::class_< T > bind(py::module& module, const char* name); template < > py::class_< MyClass > bind(py::module& module, const char* name) { return py::class_< MyClass >(module, name) .def(py::init< >(), "Constructs a new instance") // ... .def("__repr__", [](const MyClass& obj) { return "something"; }); } template < > py::class_< MyOtherClass > bind(py::module& module, const char* name) { return py::class_< MyOtherClass >(module, name) .def(py::init< >(), "Constructs a new instance") // ... .def("__repr__", [](const MyOtherClass& obj) { return module.class("MyClass").attr("__repr__")(obj.val); }); // <- 如何调用为MyClass定义的__repr__方法? } // ------------------------------------------------------------------------- PYBIND11_MODULE(pymodule, module) { // ... bind< MyClass >(module, "MyClass"); bind< MyOtherClass >(module, "MyOtherClass"); // ... }
解决方案
有两种可行方式实现MyOtherClass调用MyClass的__repr__方法:
方法1:通过模块获取已绑定的类并调用方法
利用py::module的attr()方法直接获取模块中已绑定的MyClass,再取出其__repr__方法调用。需要将C++的MyClass实例转为pybind11对象,用py::cast()完成转换:
template < > py::class_< MyOtherClass > bind(py::module& module, const char* name) { return py::class_< MyOtherClass >(module, name) .def(py::init< >(), "Constructs a new instance") .def("__repr__", [&module](const MyOtherClass& obj) { auto my_class_repr = module.attr("MyClass").attr("__repr__"); return my_class_repr(py::cast(obj.val)); }); }
注意:必须保证MyClass的绑定(即bind<MyClass>调用)在MyOtherClass之前执行,否则模块中找不到MyClass的定义。
方法2:直接复用C++层面的实现
如果不需要走Python方法调用流程,直接把MyClass的__repr__逻辑抽成独立函数,在MyOtherClass中直接调用,这种方式效率更高:
// 抽离MyClass的__repr__实现为独立函数 std::string my_class_repr(const MyClass& obj) { return "something"; } template < > py::class_< MyClass > bind(py::module& module, const char* name) { return py::class_< MyClass >(module, name) .def(py::init< >(), "Constructs a new instance") .def("__repr__", &my_class_repr); } template < > py::class_< MyOtherClass > bind(py::module& module, const char* name) { return py::class_< MyOtherClass >(module, name) .def(py::init< >(), "Constructs a new instance") .def("__repr__", [](const MyOtherClass& obj) { return my_class_repr(obj.val); }); }
内容的提问来源于stack exchange,提问作者joaocandre
相关产品推荐
相关产品推荐

