我正在开发一个嵌入Python解释器的系统,我需要从C API中构造一个给定字符串的PyObject*
。
我有一个代表字典的const char*
,其格式正确eval()
可以在Python中正常工作,即:"{'bar': 42, 'baz': 50}"
。
目前,使用PyObject*
api(表示字符串)将其作为Py_Unicode_
传递给Python,因此在我的python解释器中,我可以成功编写:
foo = eval(myObject.value)
print(foo['bar']) # prints 42
我想将此更改为自动“评估”C侧的const char*
,并返回表示已完成字典的PyObject*
。如何将此字符串转换为C API中的字典?
答案 0 :(得分:3)
有两种基本方法可以做到这一点。
第一种是简单地调用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"
,将"eval"
更改为"literal_eval"
。但真正的胜利在于你正在完成eval
在Python中所做的事情,你已经知道它正是你想要的。
另一种方法是使用编译API。在非常高的级别,您可以从"foo = eval(%s)"
和PyRun_SimpleString
构建一个Python语句。在下面,使用Py_CompileString
来解析和编译表达式(您也可以在单独的步骤中解析和编译,但这在这里没用),然后PyEval_EvalCode
在适当的全局变量和局部变量中对它进行求值。 (如果您不是自己跟踪全局变量,请使用interpreter-reflection APIs PyEval_GetLocals
和PyEval_GetGlobals
。)请注意,我提供了每个函数的超简化版本;通常你想使用其中一个兄弟功能。但是你可以在文档中轻松找到它们。