2

How to do this

c++ -> Python -> c++
 ^               |
 |               |
 -----------------
  1. C++ app is hosting python.
  2. Python creates a class, which is actually a wrapping to c/c++ object
  3. How to get access from hosting c++ to c/c++ pointer of this object created by python?

Example with code:

Imagine I have a C++ class wrapped for python (e.g. using boost.python)

// foo.cpp
#include <boost/python.hpp>

struct Cat {
   Cat (int fur=4): _fur{i} { }
   int get_fur() const { return _fur; }
private:
   int _fur;
};

BOOST_PYTHON_MODULE(foo) {
using namespace boost::python;

class_<Cat>("Cat", init<int>())
   .def("get_fur", &A::get_fur, "Density of cat's fur");

}

Now I'm hosting a python in C++. A python script creates Cat => A c++ Cat instance is created underneath. How to get a pointer to c++ instance of Cat from hosting c++ (from C++ to C++)?

#include <Python.h>

int
main(int argc, char *argv[])
{
  Py_SetProgramName(argv[0]);  /* optional but recommended */
  Py_Initialize();
  PyRun_SimpleString("from cat import Cat \n"
                     "cat = Cat(10) \n");

  // WHAT to do here to get pointer to C++ instance of Cat
   ... ??? ...

  std::cout << "Cat's fur: " << cat->get_fur() << std::endl

  Py_Finalize();
  return 0;
}

Real application The real problem is this: we have a c++ framework which has pretty complex initialization and configuration phase where performance is not critical; and then processing phase, where performance is everything. There is a python wrapping for the framework. Defining things in python is very convenient but running from python is still slower than pure c++ code. It is tempting for many reasons to do this configuration/initialization phase in python, get pointers to underneath C++ objects and then run in "pure c++ mode". It would be easy if we could write everything from scratch, but we have already pretty much defined (30 years old) c++ framework.

2
  • the class is from c++ but the instance is from python and you want to access that instance in c++? I am not sure if it is just my confusion or if you confused class/instance in the title/question Commented Nov 8, 2019 at 16:37
  • Thanks for the remark. Updated the question. Commented Nov 8, 2019 at 16:42

2 Answers 2

1
#include <Python.h>

int main(int argc, char *argv[])
{
  Py_SetProgramName(argv[0]);
  Py_Initialize();

  object module = import("__main__");
  object space = module.attr("__dict__");

  exec("from cat import Cat \n"
       "cat = Cat(10) \n",
       space);

  Cat& cat = extract<Cat&>(space["cat"]);
  std::cout<<"Cat's fur: "<< cat.get_fur() <<"\n";

  //or:

  Cat& cat2 = extract<Cat&>(space.attr("cat"));
  std::cout<<"Cat's fur: "<< cat2.get_fur() <<"\n";

  //or:

  object result = eval("cat = Cat(10)");
  Cat& cat3 = extract<Cat&>(result);
  std::cout<<"Cat's fur: "<< cat3.get_fur() <<"\n";

  Py_Finalize();
  return 0;
}
Sign up to request clarification or add additional context in comments.

Comments

0

In case the wrapper is open source, use the wrapper's python object struct from C++. Cast the PyObject * to that struct which should have a PyObject as its first member iirc, and simply access the pointer to the C++ instance.

Make sure that the instance is not deleted while you're using it by keeping the wrapper instance around in Python. When it is released, it will probably delete the wrapped C++ instance you now still are holding a pointer to.

And keep in mind that this approach is risky and fragile, as it depends on implementation details of the wrapper that might change in future versions.

Starting point: cpython/object.h

1 Comment

Could you provide some code. E.g. based on the classes in the example?

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.