When using pybind11
to expose some C++ code, is there a way to access defined classes (py::class
) from the module object (py::module
)? I understand I can use attr
directly from a bound class, but can I do the same for classes from a module?
#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_< mmyClas >(module, name)
.def(py::init< >(), "Constructs a new instance")
// ...
.def("__repr__", [](const MyOtherClass& obj) { return module.class("MyClass").attr("__repr__")(obj.val); }); // <- how to call "__repr__" defined for MyClass ?
}
// -------------------------------------------------------------------------
PYBIND11_MODULE(pymodule, module) {
// ...
bind< MyClass >(module, "MyClass");
bind< MyOtherClass >(module, "MyOtherClass");
// ...
}
Combing through pybind11's documentation, I was able to find the answer:
py::type T_py = py::type::of<T>();
I can then call the __repr__
method on an object:
py::type::of< MyClass >().attr("__repr__")(obj);
which can be made into a generic function template:
template < typename T >
inline std::string repr(const T& in) {
return py::str(py::type::of< T >().attr("__repr__")(in));
}
to simplify the syntax when binding multiple dependent types independently (i.e. without access to py::class_<>
instances).
Note: repr()
will raise an ImportError
on Python in case T
hasn't been exposed to Python.