【问题标题】:Swig exception in Python director classPython 导演类中的 Swig 异常
【发布时间】:2019-08-24 15:04:53
【问题描述】:

我在 Python 中使用 Swig 导向器包装了一些类。 我的每个类方法都返回一个 MyError 类。发生的情况是,一旦我从我的一个 C++ 派生一个 python 类并且我忘记返回 MyError() 对象但我返回 None of "pass" 或者我忘记返回任何内容,我的软件在 MyError 的默认构造函数中崩溃类通过读取访问冲突,我无法通过 try/catch 块跟踪此异常。

在 Swig 中处理这种情况的正确方法是什么?

谢谢!

【问题讨论】:

标签: python c++ exception swig


【解决方案1】:

Section 36.5.4 Exception unrolling 在 SWIG 文档中:

对于将方法调用路由到 Python 的导向器,以及将它们路由到 C++ 的代理,异常处理是一个重要的问题。默认情况下,导向器会忽略在 Python 中解析的方法调用期间发生的异常。要正确处理此类异常,有必要将它们临时转换为 C++ 异常。这可以通过 %feature("director:except") 指令来完成。在大多数情况下,以下代码就足够了:

%feature("director:except") {
    if ($error != NULL) {
        throw Swig::DirectorMethodException();
    }
}

此代码将在每次从控制器调用 Python 方法后检查 Python 错误状态,如果发生错误则抛出 C++ 异常。可以在 C++ 中捕获此异常以实现错误处理程序。目前没有关于 Python 错误的信息存储在 Swig::DirectorMethodException 对象中,但这可能会在未来发生变化。

方法调用可能源自 Python,通过代理类传递到 C++,然后通过导向器方法返回到 Python。如果此时 Python 中发生异常,该异常最好能找到返回给原始调用者的方式。这可以通过将普通的 %exception 指令与上面显示的 director:except 处理程序结合起来来完成。这是一个合适的异常处理程序的示例:

%exception {
    try { $action }
    catch (Swig::DirectorException &e) { SWIG_fail; }
}

本例中使用的类 Swig::DirectorException 实际上是 Swig::DirectorMethodException 的基类,所以它会捕获这个异常。因为在抛出 Swig::DirectorMethodException 时仍然设置 Python 错误状态,所以一旦 C 包装函数返回,Python 就会注册该异常。

示例

下面是一个示例test.i,说明了该技术:

%module test

%module(directors="1") test
%feature("director");

%feature("director:except") {
    if ($error != NULL) {
        throw Swig::DirectorMethodException();
    }
}

%exception {
    try { $action }
    catch (Swig::DirectorException &e) { SWIG_fail; }
}

%inline %{
    class MyError {
        int m_n;
    public:
        MyError(int n = 0) : m_n(n) {}
        ~MyError() {}
        int get() const { return m_n; }
    };

    class Demo {
    public:
        Demo() {}
        virtual ~Demo() {}
        virtual MyError test() { return MyError(5); }
    };

    int func(Demo* d) { return d->test().get(); }
%}

swigging和编译后,一个demo:

>>> import test
>>> d=test.Demo()  # default class implementation
>>> test.func(d)   # Call virtual method in a C++ test function.
5

以上工作正常。以下覆盖错误:

>>> class Demo2(test.Demo):  # New class
...  def test(self):         # Override virtual function
...   return 7               # But don't return a MyError object.
...
>>> d=Demo2()
>>> test.func(d)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: SWIG director type mismatch in output value of type 'MyError'

它捕获了异常并返回了一个有用的异常。下面正确覆盖:

>>> class Demo2(test.Demo):
...  def test(self):
...   return test.MyError(7)
...
>>> d=Demo2()
>>> test.func(d)
7

【讨论】:

  • 完全错过了这部分。不错的答案!
  • 附加说明,这个工作现在直到我返回某种对象,但如果我输入 pass 而不是 return,代码仍然会崩溃。有什么建议吗?
  • @LeonardoBernardini 迟到的回复。我忘记了这一点,但最近的一次投票让我又读了一遍。代码正在崩溃,因为它是结构化异常 (SEH) 而不是 C++ 异常。使用 Microsoft 编译器,使用/EHa 进行编译,您可以通过catch(...) 直接捕获它们或使用_set_se_translator 转换为C++ 异常。见this MSDN documentation
猜你喜欢
  • 2011-06-16
  • 1970-01-01
  • 1970-01-01
  • 2023-02-17
  • 1970-01-01
  • 1970-01-01
  • 2014-04-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多