简体   繁体   中英

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

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 (ie 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM