【问题标题】:Create object from string repesentation in C API从 C API 中的字符串表示创建对象
【发布时间】:2013-04-05 20:40:32
【问题描述】:

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

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

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

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

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

【问题讨论】:

  • 您确定不想为此使用ast.literal_eval 而不是eval? (其实并不影响答案,但值得思考。)
  • @abarnert 正在解析的字符串都在我的控制之下,所以我认为我不需要这样做——它总是一个包含各种浮点值、整数值、布尔值或(正确转义)字符串值。
  • 如果它总是一个包含float、int、bool和字符串reprs的字典,为什么使用literal_eval?它更简单一些,并且您可以免费获得一些验证。
  • @abarnert 如果代码更简单,那很好 - 我只是想弄清楚如何在 C API 方面处理这个问题,所以脚本只能看到字典。
  • 其实我夸大了,说它更简单; builtinsast 一样容易获得,或者更容易获得,之后它们是相同的。也许这只是一个下意识的反应……

标签: python c python-3.x


【解决方案1】:

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

第一个是简单地调用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 返回……但它应该足以让你理解这个想法。)

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

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

【讨论】:

  • 这差不多了 - 看起来 eval 需要一个元组,所以我必须将 args 包装在 PyTuple_Pack 中,但除此之外,这可行(+ 添加引用计数处理)。跨度>
  • 附带说明 - 您使用 Py_BuildValue("s", PyUnicode_FromString 的任何原因?
  • @ReedCopsey:对不起,这是一个愚蠢的错字。我打算做"(s)",构建str,然后一步构建arg tuple,而不是先构建str,然后再构建tuple。很好的收获。
  • 很好 - 带有 "(s)" 的 BuildValue 很有意义,并且简化了事情。感谢您对此的帮助!
  • @eryksun:答案中已经解释了该选项(尽管我使用了PyRun_SimpleString)。如果您只想评估字符串,它会更简单;如果你想确保你正在做与 Python 函数完全相同的事情,请调用 Python 函数。
猜你喜欢
  • 1970-01-01
  • 2015-09-08
  • 2019-03-20
  • 1970-01-01
  • 1970-01-01
  • 2017-05-02
  • 2015-08-19
  • 1970-01-01
相关资源
最近更新 更多