Python 多态异常处理:如何捕获子类异常? 我有以下两个C++异常的简单层次结构: class LIB_EXP ClusterException : public std::exception { public: ClusterException() { } ClusterException(const std::string& what) { init(what); } virtual const char* what() const throw() { return what_.c_str(); } virtual ~ClusterException() throw() {} virtual ClusterException* clone() { return new ClusterException(*this); } protected: void init(const std::string& what) { what_ = what; } private: std::string what_; }; class LIB_EXP ClusterExecutionException : public ClusterException { public: ClusterExecutionException(const std::string& jsonResponse); std::string getErrorType() const throw() { return errorType_; } std::string getClusterResponse() const throw() { return clusterResponse_; } virtual ~ClusterExecutionException() throw() {} virtual ClusterExecutionException* clone() { return new ClusterExecutionException(*this); } private: std::string errorType_; std::string clusterResponse_; }; static void boomTest(int exCase) { switch (exCase) { case 0: throw ClusterException("Connection to server failed"); break; case 1: throw ClusterExecutionException("Error X while executing in the cluster"); break; default: throw std::runtime_error("Unknown exception type"); } }

Python 多态异常处理:如何捕获子类异常? 我有以下两个C++异常的简单层次结构: class LIB_EXP ClusterException : public std::exception { public: ClusterException() { } ClusterException(const std::string& what) { init(what); } virtual const char* what() const throw() { return what_.c_str(); } virtual ~ClusterException() throw() {} virtual ClusterException* clone() { return new ClusterException(*this); } protected: void init(const std::string& what) { what_ = what; } private: std::string what_; }; class LIB_EXP ClusterExecutionException : public ClusterException { public: ClusterExecutionException(const std::string& jsonResponse); std::string getErrorType() const throw() { return errorType_; } std::string getClusterResponse() const throw() { return clusterResponse_; } virtual ~ClusterExecutionException() throw() {} virtual ClusterExecutionException* clone() { return new ClusterExecutionException(*this); } private: std::string errorType_; std::string clusterResponse_; }; static void boomTest(int exCase) { switch (exCase) { case 0: throw ClusterException("Connection to server failed"); break; case 1: throw ClusterExecutionException("Error X while executing in the cluster"); break; default: throw std::runtime_error("Unknown exception type"); } },python,c++,exception,boost,boost-python,Python,C++,Exception,Boost,Boost Python,然后,我使用boostpython将它们导出到Python,如下所示。请注意,我使用了base,以确保在转换中保留继承关系: class_<ClusterException> clusterException("ClusterException", no_init); clusterException.add_property("message", &ClusterException::what); clusterExceptionType = clusterExceptio

然后,我使用boostpython将它们导出到Python,如下所示。请注意,我使用了
base
,以确保在转换中保留继承关系:

class_<ClusterException> clusterException("ClusterException", no_init);
clusterException.add_property("message", &ClusterException::what);
clusterExceptionType = clusterException.ptr();
register_exception_translator<ClusterException>(&translateClusterException);

class_<ClusterExecutionException, bases<ClusterException> > clusterExecutionException("ClusterExecutionException", no_init);
clusterExecutionException.add_property("message", &ClusterExecutionException::what)
                         .add_property("errorType", &ClusterExecutionException::getErrorType)
                         .add_property("clusterResponse", &ClusterExecutionException::getClusterResponse);
clusterExecutionExceptionType = clusterExecutionException.ptr();
register_exception_translator<ClusterExecutionException>(&translateClusterExecutionException);

我创建了以下测试C++函数,抛出异常:

class LIB_EXP ClusterException : public std::exception {
public:
    ClusterException() { }
    ClusterException(const std::string& what) { init(what); }
    virtual const char* what() const throw() { return what_.c_str(); }
    virtual ~ClusterException() throw() {}
    virtual ClusterException* clone() { return new ClusterException(*this);  } 
protected:
    void init(const std::string& what) { what_ = what; }
private:
    std::string what_;
};

class LIB_EXP ClusterExecutionException : public ClusterException {
public:
    ClusterExecutionException(const std::string& jsonResponse);
    std::string getErrorType() const throw() { return errorType_; }
    std::string getClusterResponse() const throw() { return clusterResponse_; }
    virtual ~ClusterExecutionException() throw() {}
    virtual ClusterExecutionException* clone() { return new ClusterExecutionException(*this);  } 
private:
    std::string errorType_;
    std::string clusterResponse_;
};
static void boomTest(int exCase) {
  switch (exCase) {
    case 0:  throw ClusterException("Connection to server failed");
             break;
    case 1:  throw ClusterExecutionException("Error X while executing in the cluster");
             break;
    default: throw std::runtime_error("Unknown exception type");
  }
}

最后调用了我的C++代码> BooMexs/Cux:

的Python测试代码
import cluster
reload(cluster)
from cluster import ClusterException, ClusterExecutionException

def test_exception(exCase):
    try:
        cluster.boomTest(exCase)

    except ClusterException as ex:
        print 'Success! ClusterException gracefully handled:' \
            '\n message="%s"' % ex.message
    except ClusterExecutionException as ex:
        print 'Success! ClusterExecutionException gracefully handled:' \
            '\n message="%s"' \
            '\n errorType="%s"' \
            '\n clusterResponse="%s"' % (ex.message, ex.errorType, ex.clusterResponse)
    except:
        print 'Caught unknown exception: %s "%s"' % (sys.exc_info()[0], sys.exc_info()[1])

def main():
    print '\n************************ throwing ClusterException ***********************************************************************'
    test_exception(0)
    print '\n************************ throwing ClusterExecutionException **************************************************************'
    test_exception(1)
    print '\n************************ throwing std::runtime_error *********************************************************************'
    test_exception(2)

if __name__ == "__main__":
    main()
到目前为止,一切正常。但是,如果我从Python中删除
ClusterExecutionException
catch处理程序,则该异常将被捕获并回退到未知异常,而不是作为其基本
ClusterException
捕获

我在boostpython中尝试注册
ClusterExecutionException
的异常转换,将其注册为基础
ClusterException
,然后它被“多态”捕获,但不会被捕获为
ClusterExecutionException
。如何使
ClusterExecutionException
同时被捕获为
ClusterException
ClusterExecutionException
?当然,我已经尝试将此
ClusterExecutionException
异常注册为
ClusterException
ClusterExecutionException
,但它遵循了最后一个wins策略,并且只有一个不能同时起作用

还有别的办法解决这个问题吗

<强>更新1:< /强>此问题的全部圣杯是在C++侧发现<<代码>的类型,除了,除了CultExpExcor为EX:< /Cord>,这在C++的一方是未知的。Python将调用对应于异常动态类型的translate函数,而Python捕获静态类型未知

更新2:根据建议,将Python代码更改为以下内容,即添加
print(type(ex)。\uuuuu base\uuuuuuuuuu)
给出:

def test_exception(exCase):
    try:
        cluster.boomTest(exCase)

    except ClusterException as ex:
        print(type(ex).__bases__)
        print 'Success! ClusterException gracefully handled:' \
            '\n message="%s"' % ex.message
    except ClusterExecutionException as ex:
        print(type(ex).__bases__)
        print 'Success! ClusterExecutionException gracefully handled:' \
            '\n message="%s"' \
            '\n errorType="%s"' \
            '\n clusterResponse="%s"' % (ex.message, ex.errorType, ex.clusterResponse)
    except:
        print 'Caught unknown exception: %s "%s"' % (sys.exc_info()[0], sys.exc_info()[1])
以及输出:

************************ throwing ClusterException ***********************************************************************
(<type 'Boost.Python.instance'>,)
Success! ClusterException gracefully handled:
 message="Connection to server failed"

************************ throwing ClusterExecutionException **************************************************************
(<class 'cluster.ClusterException'>,)
Success! ClusterExecutionException gracefully handled:
 message="Error X while executing in the cluster"
 errorType="LifeCycleException"
 clusterResponse="{ "resultStatus": "Error", "errorType": "LifeCycleException", "errorMessage": "Error X while executing in the cluster" }"
Microsoft (R) COFF/PE Dumper Version 11.00.50727.1
Copyright (C) Microsoft Corporation.  All rights reserved.

Dump of file C:\ClusterDK\x64\Debug\ClusterDK.dll

File Type: DLL

Section contains the following exports for ClusterDK.dll

00000000 characteristics
5A1689DA time date stamp Thu Nov 23 09:42:02 2017
    0.00 version
       1 ordinal base
      78 number of functions
      78 number of names

ordinal hint RVA      name

      8    7 00004485 ??0ClusterException@cluster@@QEAA@AEBV01@@Z = @ILT+13440(??0ClusterException@cluster@@QEAA@AEBV01@@Z)
      9    8 00001659 ??0ClusterException@cluster@@QEAA@AEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z = @ILT+1620(??0ClusterException@cluster@@QEAA@AEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z)
     10    9 00001F1E ??0ClusterException@cluster@@QEAA@XZ = @ILT+3865(??0ClusterException@cluster@@QEAA@XZ)
     11    A 00004D4F ??0ClusterExecutionException@cluster@@QEAA@AEBV01@@Z = @ILT+15690(??0ClusterExecutionException@cluster@@QEAA@AEBV01@@Z)
     12    B 000010AA ??0ClusterExecutionException@cluster@@QEAA@AEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z = @ILT+165(??0ClusterExecutionException@cluster@@QEAA@AEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z)
     27   1A 000035D0 ??1ClusterException@cluster@@UEAA@XZ = @ILT+9675(??1ClusterException@cluster@@UEAA@XZ)
     28   1B 00003C7E ??1ClusterExecutionException@cluster@@UEAA@XZ = @ILT+11385(??1ClusterExecutionException@cluster@@UEAA@XZ)
     37   24 00002BD5 ??4ClusterException@cluster@@QEAAAEAV01@AEBV01@@Z = @ILT+7120(??4ClusterException@cluster@@QEAAAEAV01@AEBV01@@Z)
     38   25 000034D1 ??4ClusterExecutionException@cluster@@QEAAAEAV01@AEBV01@@Z = @ILT+9420(??4ClusterExecutionException@cluster@@QEAAAEAV01@AEBV01@@Z)
     46   2D 000D2220 ??_7ClusterException@cluster@@6B@ = ??_7ClusterException@cluster@@6B@ (const cluster::ClusterException::`vftable')
     47   2E 000D2248 ??_7ClusterExecutionException@cluster@@6B@ = ??_7ClusterExecutionException@cluster@@6B@ (const cluster::ClusterExecutionException::`vftable')
     52   33 00004BB5 ?clone@ClusterException@cluster@@UEAAPEAV12@XZ = @ILT+15280(?clone@ClusterException@cluster@@UEAAPEAV12@XZ)
     53   34 00004D31 ?clone@ClusterExecutionException@cluster@@UEAAPEAV12@XZ = @ILT+15660(?clone@ClusterExecutionException@cluster@@UEAAPEAV12@XZ)
     61   3C 00001D43 ?getErrorType@ClusterExecutionException@cluster@@QEBA?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@XZ = @ILT+3390(?getErrorType@ClusterExecutionException@cluster@@QEBA?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@XZ)
     69   44 0000480E ?init@ClusterException@cluster@@IEAAXAEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z = @ILT+14345(?init@ClusterException@cluster@@IEAAXAEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z)
     78   4D 000032FB ?what@ClusterException@cluster@@UEBAPEBDXZ = @ILT+8950(?what@ClusterException@cluster@@UEBAPEBDXZ)

Summary

    4000 .data
    5000 .idata
   12000 .pdata
   54000 .rdata
    2000 .reloc
    1000 .rsrc
   C9000 .text
    1000 .tls
以及输出的相关部分:

************************ throwing ClusterException ***********************************************************************
(<type 'Boost.Python.instance'>,)
Success! ClusterException gracefully handled:
 message="Connection to server failed"

************************ throwing ClusterExecutionException **************************************************************
(<class 'cluster.ClusterException'>,)
Success! ClusterExecutionException gracefully handled:
 message="Error X while executing in the cluster"
 errorType="LifeCycleException"
 clusterResponse="{ "resultStatus": "Error", "errorType": "LifeCycleException", "errorMessage": "Error X while executing in the cluster" }"
Microsoft (R) COFF/PE Dumper Version 11.00.50727.1
Copyright (C) Microsoft Corporation.  All rights reserved.

Dump of file C:\ClusterDK\x64\Debug\ClusterDK.dll

File Type: DLL

Section contains the following exports for ClusterDK.dll

00000000 characteristics
5A1689DA time date stamp Thu Nov 23 09:42:02 2017
    0.00 version
       1 ordinal base
      78 number of functions
      78 number of names

ordinal hint RVA      name

      8    7 00004485 ??0ClusterException@cluster@@QEAA@AEBV01@@Z = @ILT+13440(??0ClusterException@cluster@@QEAA@AEBV01@@Z)
      9    8 00001659 ??0ClusterException@cluster@@QEAA@AEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z = @ILT+1620(??0ClusterException@cluster@@QEAA@AEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z)
     10    9 00001F1E ??0ClusterException@cluster@@QEAA@XZ = @ILT+3865(??0ClusterException@cluster@@QEAA@XZ)
     11    A 00004D4F ??0ClusterExecutionException@cluster@@QEAA@AEBV01@@Z = @ILT+15690(??0ClusterExecutionException@cluster@@QEAA@AEBV01@@Z)
     12    B 000010AA ??0ClusterExecutionException@cluster@@QEAA@AEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z = @ILT+165(??0ClusterExecutionException@cluster@@QEAA@AEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z)
     27   1A 000035D0 ??1ClusterException@cluster@@UEAA@XZ = @ILT+9675(??1ClusterException@cluster@@UEAA@XZ)
     28   1B 00003C7E ??1ClusterExecutionException@cluster@@UEAA@XZ = @ILT+11385(??1ClusterExecutionException@cluster@@UEAA@XZ)
     37   24 00002BD5 ??4ClusterException@cluster@@QEAAAEAV01@AEBV01@@Z = @ILT+7120(??4ClusterException@cluster@@QEAAAEAV01@AEBV01@@Z)
     38   25 000034D1 ??4ClusterExecutionException@cluster@@QEAAAEAV01@AEBV01@@Z = @ILT+9420(??4ClusterExecutionException@cluster@@QEAAAEAV01@AEBV01@@Z)
     46   2D 000D2220 ??_7ClusterException@cluster@@6B@ = ??_7ClusterException@cluster@@6B@ (const cluster::ClusterException::`vftable')
     47   2E 000D2248 ??_7ClusterExecutionException@cluster@@6B@ = ??_7ClusterExecutionException@cluster@@6B@ (const cluster::ClusterExecutionException::`vftable')
     52   33 00004BB5 ?clone@ClusterException@cluster@@UEAAPEAV12@XZ = @ILT+15280(?clone@ClusterException@cluster@@UEAAPEAV12@XZ)
     53   34 00004D31 ?clone@ClusterExecutionException@cluster@@UEAAPEAV12@XZ = @ILT+15660(?clone@ClusterExecutionException@cluster@@UEAAPEAV12@XZ)
     61   3C 00001D43 ?getErrorType@ClusterExecutionException@cluster@@QEBA?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@XZ = @ILT+3390(?getErrorType@ClusterExecutionException@cluster@@QEBA?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@XZ)
     69   44 0000480E ?init@ClusterException@cluster@@IEAAXAEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z = @ILT+14345(?init@ClusterException@cluster@@IEAAXAEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z)
     78   4D 000032FB ?what@ClusterException@cluster@@UEBAPEBDXZ = @ILT+8950(?what@ClusterException@cluster@@UEBAPEBDXZ)

Summary

    4000 .data
    5000 .idata
   12000 .pdata
   54000 .rdata
    2000 .reloc
    1000 .rsrc
   C9000 .text
    1000 .tls

我的python技能已经过时了,我还没有对此进行测试,因此这可能需要进一步改进,但请尝试添加异常转换方法来处理基类异常类型:

static PyObject *clusterExecutionAsClusterExceptionType = NULL;
static void translateClusterExecutionAsClusterException(ClusterException const &exception) {

  ClusterExecutionException* upcasted = dynamic_cast<ClusterExecutionException*>(&exception);
  if (upcasted)
  {
    assert(clusterExecutionAsClusterExceptionType != NULL);
    boost::python::object pythonExceptionInstance(*upcasted);
  PyErr_SetObject(clusterExecutionAsClusterExceptionType, pythonExceptionInstance.ptr());
  }
}

register_exception_translator<ClusterException>(&translateClusterExecutionAsClusterException);
静态PyObject*clusterExecutionAsClusterExceptionType=NULL;
静态无效translateClusterExecutionAsClusterException(ClusterException常量和异常){
ClusterExecutionException*upcasted=动态强制转换(&exception);
如果(向上浇铸)
{
断言(clusterExecutionAsClusterExceptionType!=NULL);
boost::python::object pythonExceptionInstance(*upcasted);
PyErr_SetObject(clusterExecutionAsClusterExceptionType,pythonExceptionInstance.ptr());
}
}
寄存器\异常\转换器(&translateClusterExecutionAsClusterException);

我不知道你的C++代码。但是python代码有一个小问题。捕获
ClusterExecutionException
之前的
ClusterException
。您应该始终将子异常处理程序置于基本异常之前

test\u exception
中,如果引发
ClusterExecutionException
异常,则它将在到达
ClusterExecutionException
之前被
ClusterException
捕获

代码应如下代码所示

def test_exception(exCase):
    try:
        cluster.boomTest(exCase)

    except ClusterExecutionException as ex:
        print 'Success! ClusterExecutionException gracefully handled:' \
            '\n message="%s"' \
            '\n errorType="%s"' \
            '\n clusterResponse="%s"' % (ex.message, ex.errorType, ex.clusterResponse)
    except ClusterException as ex:
        print 'Success! ClusterException gracefully handled:' \
            '\n message="%s"' % ex.message
    except:
        print 'Caught unknown exception: %s "%s"' % (sys.exc_info()[0], sys.exc_info()[1])

现在,我尝试在Boost Python中注册ClusterExecutionException的异常转换,以将其注册为其基础ClusterException,正如您刚才提到的。

在注册这两种方法时,是否也重载了基类类型的translateClusterExecutionException(..)方法?您可能需要将&ref()动态转换为派生指针类型才能再次获得正确的行为。。。最好是一个尽可能详细的答案,我将对其进行测试…当您删除除ClusterExecutionException之外的行
,例如:…
,您能验证您得到的异常的基类吗?e、 g.
例外情况除外,如e:print(键入(e)。\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu!在OP中创建了更新2,它正确地显示了基类。由于
ClusterExecutionException
的基类是
cluster.ClusterException
,您是否尝试过捕获异常
除了cluster.ClusterException之外的异常,例如:
?谢谢,我已经尝试了您发布的内容,但它不起作用。我也尝试过它的多种推导,但都没有成功。这个问题的圣杯是异常类型映射,使它与C++中未知的“catch”语句中的Python异常类型相匹配。这是一段时间,但我只是想到了一些东西。如果您能够从包含函数/对象签名的python dll转储所有导出的符号(dumpbin.exe),那么您可能能够拼凑触发异常所需的签名。这一点很好!我更新了问题。若我们找到一个解决方案,我将很高兴接受你们的回答,并要求转移100分给你们。谢谢你们,但这是一个评论,而不是一个答案。异常处理中的顺序不是通常的顺序,这也说明了我在OP中描述的问题。如果问题是你所回答的,我会一直处理
ClusterException
,因为它会以多态方式落在基类上,但它不工作,因此OP。我把它放在答案上,因为我没有评论的特权。啊,好的,得到了你:)这个答案加上100分完全是误导。。。这个答案只指出了我所知道的一个最佳实践,而没有解决OP。访问这个问题的人会浪费时间,因为他们认为OP的解决方案只是重新排序异常处理。另一个答案是更值得获得100分,并在顶部。