c++ooppybind11

How to access bound classes from a `py::module` object?


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");
    // ...

}

Solution

  • 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.