abi*_*ham 8 python exception abstract-base-class
假设我有一个带有抽象基类的异常类,如下所示:
class MyExceptions(BaseExeption, metaclass=abc.ABCMeta):
pass
class ProperSubclass(MyExceptions):
pass
MyExceptions.register(ValueError)
Run Code Online (Sandbox Code Playgroud)
看来,我能赶上ProperSubclass的MyExceptions,但不是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.')
Run Code Online (Sandbox Code Playgroud)
所以我的问题是,我是否应该能够通过抽象基类捕获内置异常?如果是这样,怎么样?如果没有,那么规则是什么?
我想提出这个的另一种方式是:为匹配做,除非条款正确使用isinstance()/ issubclass(),如果没有(如出现这种情况)什么做他们使用?也许在C实现中有一些阴暗的快捷方式.
该文件说:
如果对象是异常对象的类或基类,或者包含与异常兼容的项的元组,则该对象与异常兼容.
不幸的是,这并没有说明是否应该考虑虚拟基类,这与例如issubclass的语言不同:
如果class是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);
Run Code Online (Sandbox Code Playgroud)
作为参考,issubclass的CPython实现,PyObject_IsSubclass,__subclasscheck__在回退之前调用PyType_IsSubtype.
所以这种行为有充分的理由; 异常处理需要是非递归的,因此它回调到Python代码是不安全的.请注意,Python 2.7版本接受溢出的风险并进行调用PyObject_IsSubclass.有人建议在Python 3中放宽这个限制,但是虽然已经编写了补丁但尚未被接受.否则,文档澄清except检查是非虚拟的是一个好主意.