4

我正在开发一个嵌入 Python 解释器的系统,我需要PyObject*从 C API 构造一个给定的字符串。

我有一个const char*表示字典,格式eval()正确,可以在 Python 中正常工作,即:"{'bar': 42, 'baz': 50}".

目前,这是作为PyObject*使用Py_Unicode_api (表示字符串)传递给 Python 的,所以在我的 python 解释器中,我可以成功编写:

foo = eval(myObject.value)
print(foo['bar']) # prints 42

我想将其更改为const char*在 C 端自动“评估”,并返回一个PyObject*表示已完成的字典。如何在 C API 中将此字符串转换为字典?

4

1 回答 1

4

有两种基本方法可以做到这一点。

第一个是简单地调用eval你在 Python 中所做的相同方式。唯一的窍门是你需要一个builtins模块句柄,因为你不能在 C API 中免费获得它。有很多方法可以做到这一点,但一种非常简单的方法是直接导入它:

/* or PyEval_GetBuiltins() if you know you're at the interpreter's top level */
PyObject *builtins = PyImport_ImportModule("builtins");
PyObject *eval = PyObject_GetAttrString(builtins, "eval");
PyObject *args = Py_BuildValue("(s)", expression_as_c_string);
PyObject *result = PyObject_Call(eval, args);

(这是未经测试的代码,它至少会泄漏引用,并且如果你想在 C 端处理异常,它不会检查 NULL 返回……但它应该足以理解这个想法。)

关于这一点的一件好事是您可以ast.literal_eval以完全相同的方式使用eval(这意味着您可以获得一些免费验证);只需更改"builtins""ast"和。但真正的胜利在于,您所做的正是Python 中所做的事情,而您已经知道这正是您想要的。"eval""literal_eval"eval

另一种方法是使用编译 API。在真正的高层次上,你可以用它构建一个 Python"foo = eval(%s)"语句PyRun_SimpleString。在此之下,Py_CompileString用于解析和编译表达式(您也可以在单独的步骤中解析和编译,但这在这里没有用),然后PyEval_EvalCode在适当的全局变量和局部变量中对其进行评估。(如果您自己不跟踪全局变量,请使用解释器反射 API PyEval_GetLocalsPyEval_GetGlobals.)请注意,我给出了每个函数的超级简化版本;通常你想使用其中一个兄弟函数。但是您可以在文档中轻松找到它们。

于 2013-04-05T20:56:18.847 回答