2

I try to embed a python interpreter into my C++17 application. I must access an object instance of Foo, which lives in the C++-world, from python.

So I came up with following code:

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

namespace py = pybind11;
using namespace py::literals;

class Foo
{
public:
  Foo() : v(42) {}
  int get() const { return v; }
  void set(int x) { v = x; }
private:
  int v;
};

PYBIND11_EMBEDDED_MODULE(my_module, m) {
    py::class_<Foo>(m, "Foo")
      .def(py::init<>())
      .def("get", &Foo::get)
      .def("set", &Foo::set);
}

int main()
{
  py::scoped_interpreter guard{};
  using namespace py::literals;

  py::object py_foo = py::cast(Foo());
  auto locals = py::dict(
    "foo"_a = py_foo            // (line of evil)
  );

  // CRASH!
  try {
    py::exec("print(foo.get())", py::globals(), locals);
    return EXIT_SUCCESS;
  } catch (const std::exception& e) {
    std::cerr << e.what() << std::endl;
    return EXIT_FAILURE;
  }
}

which crashes at runtime: Unable to convert call argument 'foo' of type 'object' to Python object

The docs only show how to insert int and string into a py::dict.

I guess pybind11 knows about Foo, since when I remove the line (line of evil) and replace the code with from my_module import Foo; print(Foo().get()), it does what I expect (but obviously not what I intend).

So, what am I doing wrong?

1 Answer 1

5

In embedded Python interpreter, you need to import the module first, otherwise Python doesn't know that module exists.

Add py::module::import("my_module"); to your main():

int main()
{
  py::scoped_interpreter guard{};

  py::module::import("my_module");  // <-- Here, import the module
  using namespace py::literals;

  py::object py_foo = py::cast(Foo());
  auto locals = py::dict(

// ....
Sign up to request clarification or add additional context in comments.

3 Comments

Thanks! Any idea on how to improve docs about that? I didn't find a hint. Or am I just too dizzy?
@pasbi IDK where in the docs it is written... Actually this is kinda intuitive. Because that macro just defines a module and nothing else. In the standalone library case, you need to import that module from Python before use it. So it's similar for embedded case.
Sure, now it totally makes sense to me, too. But if you're new to pybind11 and everything feels magic, it's hard to debug. So I guess an example like that wouldn't be inappropriate to put into the docs. Note that, in plain python, you can use objects from modules that were not directly imported into current scope (see git.io/fppLV). Maybe that mislead me.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.