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.
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:
globals()
. If the second argument is omitted, then it is also used for locals()
.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++