Please consider the following C++ pybind11 program:
#include <pybind11/embed.h>
namespace py = pybind11;
int main() {
py::scoped_interpreter guard{};
py::dict locals;
py::exec(R"(
import sys
def f():
print(sys.version)
)", py::globals(), locals);
locals["f"](); // <-- ERROR
}
The py::exec
call and the enclosed import sys
call both succeed, but the call locals["f"]()
throws an exception:
NameError: name 'sys' is not defined
on the first line of function f
.
Expected behaviour is that the program prints the python system version.
Any ideas?
Update:
I modified the program as suggested by @DavidW:
#include <pybind11/embed.h>
namespace py = pybind11;
int main() {
py::scoped_interpreter guard{};
py::dict globals = py::globals();
py::exec(R"(
import sys
def f():
print(sys.version)
)", globals, globals);
globals["f"](); // <-- WORKS NOW
}
and it now works.
I'm not 100% sure I understand what is going on, so I would appreciate an explanation.
(In particular does the modification of the common globals
/ locals
dictionary impact any other scripts. Is there some global dictionary that is part of the python interpreter that the exec
script is modifying? or does py::globals()
take a copy of that state so the execed script is isolated from other scripts?)
Update 2:
So it looks like having globals and locals be the same dictionary is the default state:
$ python
>>> globals() == locals()
True
>>> from __main__ import __dict__ as x
>>> x == globals()
True
>>> x == locals()
True
...and that the default value for the two is __main__.__dict__
, whatever that is (__main__.__dict__
is the dictionary returned by py::globals()
)
I'm still not clear what exactly __main__.__dict__
is.