Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Wrapping a C++ allocated instance with pybind11

When embedding python in C++ through PyBind11, I got stuck on the following issue. Consider I generate a shared_ptr instance of an object through C++ and I then want to handover this pointer to pybind11 to generate a "shadow" python binding for it.

Here is my initial, non-working attempt:

#include <stdio.h>
#include <pybind11/pybind11.h>
#include <pybind11/embed.h>

using namespace std;
namespace py = pybind11;

class Pet 
{
public:
    Pet() {}
    void bark(void) { printf("wow!\n"); }
};

PYBIND11_PLUGIN(Pets) {
    py::module m("Pets", "Say hello to our pets");

    py::class_<Pet, shared_ptr<Pet>>(m, "Pet")
        .def("bark", &Pet::bark)
      ;
    return m.ptr();
}

int main(int argc, char *argv[])
{
  py::scoped_interpreter guard{};
  shared_ptr<Pet> pet = make_shared<Pet>();

  // How do Ι "assign" Pet.pet to the C++ pet? This compiles,
  // but throws a run time exception:
  py::globals()["pet"] = py::cast(pet);

  py::exec("pet.bark()\n");
}

So my questions are:

  • So how can I create a "shadow class" for C++ shared_ptr?
  • How can I "assign" a C++ shared_ptr to a python variable?
like image 374
Dov Grobgeld Avatar asked May 20 '26 19:05

Dov Grobgeld


1 Answers

If you check the resulting py::object from the cast (e.g. by casting it to bool), you will see that the call failed. The reason is that the python does not know the class "Pet" (nor shared_ptr). You can either use the code as above and create a module from it the usual way, then import that in a main program. Or, use the EMBEDDED_MODULE feature, which is closer to what you appear to be going for.

Adjusting your example:

#include <stdio.h>
#include <pybind11/pybind11.h>
#include <pybind11/embed.h>

using namespace std;
namespace py = pybind11;

class Pet
{
public:
    Pet() {}
    void bark(void) { printf("wow!\n"); }
};

PYBIND11_EMBEDDED_MODULE(Pets, m) {
    py::class_<Pet, shared_ptr<Pet>>(m, "Pet")
        .def("bark", &Pet::bark)
    ;
}

int main(int argc, char *argv[])
{
  py::scoped_interpreter guard{};
  shared_ptr<Pet> pet = make_shared<Pet>();

  auto pets_mod = py::module::import("Pets");

  py::globals()["pet"] = py::cast(pet);
  py::exec("pet.bark()\n");
}
like image 80
Wim Lavrijsen Avatar answered May 23 '26 08:05

Wim Lavrijsen



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!