【问题标题】:How to get an error message as string in CPython如何在 Python 中将错误消息作为字符串获取
【发布时间】:2020-11-05 15:22:32
【问题描述】:

当我在 C++ 中调用 PyRun_SimpleString(...) 并且我的 Python 脚本包含无效语法或错误时,我会收到一条错误消息并打印到我的控制台。

如何阻止该错误消息刷新到控制台,而是将该错误消息作为 stringconst char* 并可能以我自己的方式使用该字符串(显示它作为 GUI 文本或其他东西)?

【问题讨论】:

    标签: python c++ embed cpython


    【解决方案1】:

    PyRun_SimpleStringPyRun_SimpleStringFlags 的简化接口,并为PyRun_SimpleStringFlags 引用docs

    如果出现错误,则无法获取异常信息。

    也很重要,

    请注意,如果引发了其他未处理的 SystemExit,只要未设置 Py_InspectFlag,此函数将不会返回 -1,而是退出进程。

    你可能不想要那个。


    您应该改用PyRun_StringPyRun_StringFlags。可能是PyRun_StringFlags,因为它可以让您记住__future__ 导入的效果。

    PyRun_StringFlags 具有以下签名:

    PyObject* PyRun_StringFlags(const char *str, int start, PyObject *globals, PyObject *locals, PyCompilerFlags *flags)

    • str 是要运行的源字符串。

    • startPy_eval_inputPy_file_inputPy_single_input,具体取决于您是否希望它的行为类似于 eval、运行脚本或交互运行语句。 Py_eval_input 只允许一个表达式,其值将从PyRun_StringFlags 调用返回。 Py_single_input 执行表达式自动打印之类的操作,并且只允许一个(可能是复合的)语句。您可能需要Py_file_inputPy_single_input(如果您使用Py_single_input,您可能需要自定义sys.displayhook)。

    • globalslocals 是要使用的全局和本地字典,就像调用 execeval 时一样。您可能想要获取__main__ 模块的__dict__,如下所示:

      m = PyImport_AddModule("__main__");
      if (m == NULL)
          /* bad stuff happened */
          do_something_about_that();
      Py_INCREF(m);
      d = PyModule_GetDict(m);
      ...
      /* later, when you're done with m and d */
      Py_DECREF(m);
      

      并为这两个参数使用d

      PyImport_AddModulePyModule_GetDict 都返回借用的引用,但我使用 Py_INCREF 来获取 m 的新引用,并在完成引用后使用 Py_DECREF。这是因为引用 PyImport_AddModule 返回是从 sys.modules['__main__'] 借来的,并且有可能从 sys.modules删除 __main__。 (d 没有这种担心,因为这是从__main__.__dict__ 借来的,只要__main__ 本身存在,就不能删除或重新分配。只要我们的m 引用是安全的,d 就是安全的。 )

    • flags 是指向具有一个相关字段的结构的指针,int 表示编译器标志。 __future__ 导入会影响此字段。为确保来自一次 PyRun_StringFlags 调用的 __future__ 语句在下一次调用中仍然处于活动状态,您应该在运行之间不会被释放或擦除的地方创建一个结构:

      PyCompilerFlags flags = {0};
      

      并将&flags 作为此参数传递。如果你不想想记住__future__语句的效果,你可以传递NULL,或者使用PyRun_String,它没有这个参数。


    PyRun_StringFlags 将在成功时返回一个 Python 对象(通常是 None,并记得取消引用),在异常时返回 NULL。如果有异常,可以通过C-level API for exception handling,特别是PyErr_FetchPyErr_NormalizeExceptionPyException_SetTraceback进行检查。

    在设置异常时运行以下命令:

    PyObject *type, *val, *tb;
    PyErr_Fetch(&type, &val, &tb);
    

    是一种 C 级别,相当于输入 except 块并获取 sys.exc_info(),除了 val 可能是 NULL 或不是 type 的实例,以及异常的 __traceback__ 属性可能没有设置。以下:

    PyErr_NormalizeException(&type, &val, &tb);
    if (tb != NULL) {
      PyException_SetTraceback(val, tb);
    }
    

    如果你需要,进行标准化。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-04-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-12-12
      相关资源
      最近更新 更多