user947871
user947871

Reputation: 339

Get a c++ pointer to a Python instance using Boost::Python

I am working on embedding Python inside of a C++ application. When I create a new object in Python, I want to be able to store a reference to that Object in my C++ application, so that I can later call methods on that object. What's the recommended way of doing this?

For Example, I would like to be able to do something like this :

Entity.py

class Entity:
    def getPointer(self)
        return pointertoSelf;

Manager.cpp

Py_Initialize();
PyRun_SimpleString("import Entity");
PyRun_SimpleString("entity = Entity.Entity()");

pointerToPythonObj* = somehowGetPointerToObj("entity");

Upvotes: 3

Views: 708

Answers (1)

Tanner Sansbury
Tanner Sansbury

Reputation: 51871

The recommended way is to query into the namespace in which the entity object was created, then store a handle to the entity object as a boost::python::object. When interacting with Python objects from C++, it is best to use boost::python::object whenever possible, as it provides a high-level notation that acts much like a Python variable. Additionally, it provides the appropriate reference counting to manage the lifetime of the Python object. For example, storing a raw pointer (i.e. pointerToPythonObj* ) would not extend the life of the Python object; if the Python object was garbage collected from within the interpreter, then pointerToPythonObj would be a dangling pointer.


Here is an example demonstrating this:

Entity.py:

class Entity:
    def action(self):
        print "in Entity::action"

main.cpp:

#include <boost/python.hpp>

int main()
{
  namespace python = boost::python;
  try
  {
    Py_Initialize(); // Start interpreter.

    // Create the __main__ module.
    python::object main = python::import("__main__");
    python::object main_namespace = main.attr("__dict__");

    // Import Entity.py, and instantiate an Entity object in the
    // global namespace.  PyRun_SimpleString could also be used,
    // as it will default to running within and creating 
    // __main__'s namespace.
    exec(
        "import Entity\n"
        "entity = Entity.Entity()\n"
      , main_namespace
    );

    // Obtain a handle to the entity object created from the previous
    // exec.
    python::object entity = main_namespace["entity"];
    // Invoke the action method on the entity.
    entity.attr("action")();
  }
  catch (const python::error_already_set&)
  {
    PyErr_Print();
  }
}

Running the above program results in the following output:

in Entity::action

If Entity.py is failing to be imported, then it may require adding its containing directory to the PYTHONPATH environment variable.

Upvotes: 2

Related Questions