基于抽象基类捕获异常



假设我有一个抽象基类的异常类,如下所示:

class MyExceptions(BaseExeption, metaclass=abc.ABCMeta):
    pass
class ProperSubclass(MyExceptions):
    pass
MyExceptions.register(ValueError)

似乎我可以通过MyExceptions捕获ProperSubclass,但不能捕获ValueError:

try:
    raise ProperSubclass()
except MyExceptions:
    print('As expected, control comes here...')
except:
    print('...and not here.')
try:
    raise ValueError()
except MyExceptions:
    print('Control does not come here...')
except ValueError:
    print('...but unexpectedly comes here.')

所以我的问题是,我应该能够捕获内置异常的抽象基类吗?如果有,怎么做?如果没有,规则是什么?

我想问这个问题的另一种方式是:是否except子句正确地使用isinstance()/issubclass()进行匹配,如果不是(似乎是这种情况)他们使用什么 ?也许在C实现中有一些阴暗的快捷方式

文档说:

如果对象是异常对象的类或基类,或者是包含与异常兼容的项的元组,则该对象与异常兼容。

不幸的是,这并没有说明是否应该考虑虚拟基类,不像语言中的issubclass:

如果classinfo的子类(直接的、间接的或虚的)返回true。[…]

重写实例和子类检查的语言也没有多大帮助:

以下方法用于覆盖isinstance()issubclass()内置函数的默认行为。[…]

事实上,正如您所怀疑的,CPython实现(对于Python 3)绕过子类检查,直接调用PyType_IsSubtype:

http://hg.python.org/cpython/file/3.4/Python/errors.c l167

PyErr_GivenExceptionMatches(PyObject *err, PyObject *exc)
{
    ...
        /* PyObject_IsSubclass() can recurse and therefore is
           not safe (see test_bad_getattr in test.pickletester). */
        res = PyType_IsSubtype((PyTypeObject *)err, (PyTypeObject *)exc);

作为参考,issubclass的CPython实现PyObject_IsSubclass在回退到PyType_IsSubtype之前调用__subclasscheck__

所以这种行为有一个很好的理由;异常处理需要是非递归的,因此回调到Python代码中是不安全的。请注意,Python 2.7版本接受溢出风险并调用PyObject_IsSubclass。在Python 3中有一个放宽此限制的建议,但是尽管已经编写了补丁,但尚未被接受。否则,最好在文档中澄清except检查是非虚拟的。

相关内容

  • 没有找到相关文章

最新更新