有两种基本方法可以做到这一点。
第一个是简单地调用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_GetLocals
和PyEval_GetGlobals
.)请注意,我给出了每个函数的超级简化版本;通常你想使用其中一个兄弟函数。但是您可以在文档中轻松找到它们。