Question

I am embedding python in my C++ application, using boost python.

I would like to be able to call a boost python function object, and associate a global name space with that function call. Specifically, the simplified relevant code is:

bp::object main = bp::import("__main__");
bp::object main_namespace = main.attr("__dict__");


//Put the function name runPyProg in the main_namespace

bp::object PyProg = exec(
        "import cStringIO\n"
        "import sys\n"
        "sys.stderr = cStringIO.StringIO()\n"
        "def runPyProg(exp):\n"
        "    print exp\n"
        "    exec(exp)\n"
        "    return\n"
        "\n",main_namespace);

//Now call the python function runPyProg with an argument

bp::object py_fn = main.attr("runPyProg");
py_fn(expStr)

I know that when I use the boost python exec() function, I can send in the global namespace, as shown above. My question is how do I associate main_namespace with the python function when I call py_fn? My final goal is that local variables from runPyProg will be placed in the main_namespace.

Thank you.

Was it helpful?

Solution

If I understand the question correctly, then it should be as simple as specifying the context in which exec will execute. A function or method can access the namespace in which it is defined via globals(). Thus, calling globals() from within runPyProg() will return the Python equivalent of main_namespace. Additionally, exec takes two optional arguments:

  • The first argument specifies the dictionary that will be used for globals(). If the second argument is omitted, then it is also used for locals().
  • The second argument specifies the dictionary that will be used for locals(). Variable changes occurring within exec are applied to locals().

Therefore, change:

exec exp

to

exec exp in globals()

and it should provide the desired behavior, where exp can interact with global variables in main_namespace.


Here is a basic example:

#include <boost/python.hpp>

int main()
{
  Py_Initialize();

  namespace python = boost::python;
  python::object main = python::import("__main__");
  python::object main_namespace = main.attr("__dict__");

  //Put the function name runPyProg in the main_namespace
  python::exec(
    "def runPyProg(exp):\n"
    "    print exp\n"
    "    exec exp in globals()\n"
    "    return\n"
    "\n", main_namespace);

  // Now call the python function runPyProg with an argument
  python::object runPyProg = main.attr("runPyProg");

  // Set x in python and access from C++.
  runPyProg("x = 42");
  std::cout << python::extract<int>(main.attr("x")) << std::endl;

  // Set y from C++ and access within python.
  main.attr("y") = 100;
  runPyProg("print y");

  // Access and modify x in python, then access from C++.
  runPyProg("x += y");
  std::cout << python::extract<int>(main.attr("x")) << std::endl;
}

Commented output:

x = 42          // set from python
42              // print from C++
                // y set to 100 from C++
print y         // print y from python
100             //
x += y          // access and modify from python
142             // print x from C++
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top