【发布时间】:2022-01-10 18:35:17
【问题描述】:
我有一个带有自定义异常的 C++ 库,该异常源自 std::runtime_error。它代表了一种断言失败,所以我想将它映射到 python 中的 AssertionError 。到目前为止,这很容易:
%exception {
try {
$action
} catch(MyNamespace::Assertion& e) {
PyErr_SetString(PyExc_AssertionError, e.what() );
return nullptr;
} catch(...) {
PyErr_SetString(PyExc_RuntimeError, "Unknown Exception");
return nullptr;
}
}
这很好用。
问题是我刚刚在 C++ 中向 MyNamespace::Assertion 添加了一个数据成员,我想将它传播到 python 异常。问题(以及与之前已经回答的类似问题不同的原因)是我希望 python 中的异常类型从 AssertionError 派生。如果客户端关心新数据成员,他们可以显式捕获它,但如果客户端不关心,我希望他们能够捕获 AssertionError 并让它工作。
我可以添加我自己的从 AssertionError 派生的异常类型并将 C++ 断言映射到它
%{
static PyObject* p_MyAssertionError;
%}
%init %{
p_MyAssertionError = PyErr_NewException("_MyModule.MyAssertionError",PyExc_AssertionError, NULL);
Py_INCREF(p_MyAssertionError);
PyModule_AddObject(m, "MyAssertionError", p_MyAssertionError);
%}
%pythoncode %{
MyAssertionError = _MyModule.MyAssertionError
%}
%exception {
try {
$action
} catch(MyNamespace::Assertion& e) {
PyErr_SetString(p_MyAssertionError, e.what() );
return nullptr;
} catch(...) {
PyErr_SetString(PyExc_RuntimeError, "Unknown Exception");
return nullptr;
}
}
这也很好用。问题是现在我想将新数据成员添加到 python 异常中,但我不知道该怎么做(我对 python API 不是很熟悉)。从我在 PyErr_NewException 的文档中看到的内容来看,第三个参数可以是要添加的属性字典,所以我想这将是解决方案的一部分,但我没有看到任何关于如何做到这一点的示例。文档只是说这个参数通常为NULL。
另一个问题是,如果我使用 PyErr_NewException 创建自己的派生异常类型,如何在 %exception 块上构造一个?我假设我需要使用 PyErr_SetObject() 而不是 PyErr_SetString(),虽然我看到了如何使用 PyErr_SetObject() 创建完全自定义类型的异常的示例,但我没有看到任何创建一个派生自标准异常类型,但具有附加属性。
【问题讨论】:
-
我感觉我曾经回答过类似的问题,但我现在找不到它,所以再写一个......