python - 如何在 SWIG 包装器库中将 C++ 异常传播到 Python?

标签 python exception swig

我正在围绕自定义 C++ 库编写 SWIG 包装器,该库定义了自己的 C++ 异常类型。该库的异常类型比标准异常更丰富、更具体。 (例如,一个类表示解析错误并具有一组行号。)如何在保留异常类型的同时将这些异常传播回 Python?

最佳答案

我知道这个问题已经有几个星期了,但我在为自己研究解决方案时才发现它。所以我会尝试回答,但我会提前警告它可能不是一个有吸引力的解决方案,因为 swig 接口(interface)文件可能比手动编码包装器更复杂。此外,据我所知,swig 文档从不直接处理用户定义的异常。

假设您想从您的 c++ 代码模块 mylibrary.cpp 中抛出以下异常,并在您的 python 代码中捕获一些错误消息:

throw MyException("Highly irregular condition...");  /* C++ code */

MyException 是在别处定义的用户异常。

在开始之前,请记下应该如何在您的 python 中捕获此异常。出于我们的目的,假设您有如下 Python 代码:

import mylibrary
try:
    s = mylibrary.do_something('foobar')
except mylibrary.MyException, e:
    print(e)

我认为这描述了您的问题。

我的解决方案包括在您的 swig 接口(interface)文件 (mylibrary.i) 中添加四个如下内容:

第 1 步: 在头指令(通常未命名的 %{...%} block )中添加指向 Python 感知异常的指针的声明,我们将其称为 pMyException。下面的第 2 步将对此进行定义:

%{
#define SWIG_FILE_WITH_INIT  /* for eg */
extern char* do_something(char*);   /* or #include "mylibrary.h" etc  */
static PyObject* pMyException;  /* add this! */
%}

第 2 步: 添加一个初始化指令(“m”特别令人震惊,但这正是 swig v1.3.40 目前在其构造的包装文件中需要的) - pMyException 在上面的步骤 1 中声明:

%init %{
    pMyException = PyErr_NewException("_mylibrary.MyException", NULL, NULL);
    Py_INCREF(pMyException);
    PyModule_AddObject(m, "MyException", pMyException);
%}

第 3 步: 如前一篇文章所述,我们需要一个异常指令——注意“%except(python)”已被弃用。这会将 c++ 函数“do_something”包装在一个 try-except block 中,该 block 捕获 c++ 异常并将其转换为上面第 2 步中定义的 python 异常:

%exception do_something {
    try {
        $action
    } catch (MyException &e) {
        PyErr_SetString(pMyException, const_cast<char*>(e.what()));
        SWIG_fail;
    }
}

/* The usual functions to be wrapped are listed here: */
extern char* do_something(char*);

第 4 步: 因为 swig 在 .pyd dll 周围设置了一个 python 包装(一个“影子”模块),所以我们还需要确保我们的 python 代码可以“透视”到 .pyd 文件。以下对我有用,最好直接编辑 swig py 包装器代码:

%pythoncode %{
    MyException = _mylibrary.MyException
%}

对原始海报有多大用处可能为时已晚,但也许其他人会发现上面的一些有用的建议。对于小型作业,您可能更喜欢手工编码的 c++ 扩展包装器的简洁性,而不是 swig 接口(interface)文件的困惑。


添加:

在我上面列出的接口(interface)文件中,我省略了标准模块指令,因为我只想描述使异常工作所需的附加内容。但是你的模块行应该是这样的:

%module mylibrary

此外,您的 setup.py(如果您使用的是 distutils,我建议您至少开始使用)应该具有类似于以下的代码,否则当 _mylibrary 无法识别时,第 4 步将失败:

/* setup.py: */
from distutils.core import setup, Extension

mylibrary_module = Extension('_mylibrary', extra_compile_args = ['/EHsc'],
                    sources=['mylibrary_wrap.cpp', 'mylibrary.cpp'],)

setup(name="mylibrary",
        version="1.0",
        description='Testing user defined exceptions...',
        ext_modules=[mylibrary_module],
        py_modules = ["mylibrary"],)

注意编译标志/EHsc,我在 Windows 上需要它来编译异常。您的平台可能不需要该标志;谷歌有详细信息。

我已经使用我自己的名称测试了代码,我在此处将其转换为“mylibrary”和“MyException”,以帮助概括解决方案。希望转录错误很少或没有。要点是 %init 和 %pythoncode 指令以及

static PyObject* pMyException;

在头指令中。

希望澄清解决方案。

关于python - 如何在 SWIG 包装器库中将 C++ 异常传播到 Python?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1394484/

相关文章:

python - 防止 Django 级联删除父类(super class)

python - 使用 Python 对 C 代码进行单元测试的最简单方法

java - 是否有 Apache Jena 的 C/C++ 绑定(bind)?

exception - Kotlin 协程无法处理异常

node.js - Node.js 的集中错误处理和报告

Android NDK 混合 C 和 C++ 错误未定义对 mult(int, int) 的引用

python - Django:N个应用程序共享1个数据库

python - 在 pymysql 中使用正确的语法将 python 变量传递给查询

Python 索引错误 : list index out of range

c# - WinApp 窗体崩溃,没有任何错误或异常 .Net