从C API中的字符串表示创建对象

时间:2013-04-05 20:40:32

标签: python c python-3.x

我正在开发一个嵌入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中的字典?

1 个答案:

答案 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_evaleval完全相同的方式(这意味着您可以获得一些免费验证);只需将"builtins"更改为"ast",将"eval"更改为"literal_eval"。但真正的胜利在于你正在完成eval在Python中所做的事情,你已经知道它正是你想要的。

另一种方法是使用编译API。在非常高的级别,您可以从"foo = eval(%s)"PyRun_SimpleString构建一个Python语句。在下面,使用Py_CompileString来解析和编译表达式(您也可以在单独的步骤中解析和编译,但这在这里没用),然后PyEval_EvalCode在适当的全局变量和局部变量中对它进行求值。 (如果您不是自己跟踪全局变量,请使用interpreter-reflection APIs PyEval_GetLocalsPyEval_GetGlobals。)请注意,我提供了每个函数的超简化版本;通常你想使用其中一个兄弟功能。但是你可以在文档中轻松找到它们。