我正在使用boost :: python在C ++中构建嵌入式python应用程序。嵌入式环境将自身的一部分导出为模块,换句话说,在环境中运行的python代码将无法在标准python env中运行,因为无法导入嵌入式模块。
对调试真正有用的功能之一是调试外壳,我可以在其中调试并手动输入标准python表达式以检查/修改当前状态。我的问题是我不知道/不知道是eval(例如“ 2 + 2”)还是exec(例如“ a = 2 + 2”)。如果我exec(“ 2 + 2”)我没有得到结果,并且如果我eval(“ a = 2 + 2”)我得到了语法错误。 (基于C背景,我不太理解为什么存在这种区别)。首先尝试评估,如果失败则执行,这似乎是一个非常可疑的解决方案,至少是由于副作用。
据我所见,boost :: python只是复制python的eval / exec函数,所以这个问题更多的是在python级别,但是我希望得到的答案是如何在C ++上做到(理想情况下)提升)级别。是否有一些极其复杂的正则表达式可用于区分可执行代码和可评估代码?目前,我只是采用一种丑陋的解决方案,即让用户决定在表达式上添加前缀。
这是一个带有TODO的MCVE,需要我在eval和exec之间进行选择(obv。需要python-dev和boost_python libs)
// g++ $(python3-config --cflags) so.cpp -fPIC -lboost_python3 $(python3-config --ldflags)
#include <boost/python.hpp>
#include <string>
#include <iostream>
namespace py = boost::python;
std::string pyobject_to_string(PyObject* obj)
{
PyObject* repr = PyObject_Str(obj);
PyObject* str = PyUnicode_AsEncodedString(repr, "utf-8", "~E~");
const char *bytes = PyBytes_AS_STRING(str);
Py_XDECREF(repr);
Py_XDECREF(str);
return std::string(bytes);
}
int main(int argc, const char** argv)
{
// Init python env
Py_Initialize();
if (argc < 2)
{
return 1;
}
try
{
// TODO decide, based on argv[1], which needs to be called, this:
py::object res = py::eval(argv[1]);
std::cout << pyobject_to_string(res.ptr()) << std::endl;
// or this:
py::exec(argv[1]);
// or something else entirely...?
}
catch(py::error_already_set&)
{
if (PyErr_Occurred())
{
PyObject *type, *value, *traceback;
PyErr_Fetch(&type, &value, &traceback);
std::string message = pyobject_to_string(type) + ":" + pyobject_to_string(value);
//PyErr_Restore(type, value, traceback);
std::cerr << message << std::endl;
}
else
{
std::cerr << "unknown error" << std::endl;
return 1;
}
}
}
示例输出为:
$ ./a.out 2+2
4
$ ./a.out a=2+2
<class 'SyntaxError'>:('invalid syntax', ('<string>', 1, 2, 'a=2+2'))
非常感谢