如何解决为什么引发异常会调用__subclasscheck__?
考虑以下示例,该示例使用__subclasscheck__
作为自定义异常类型:
class MyMeta(type):
def __subclasscheck__(self,subclass):
print(f'__subclasscheck__({self!r},{subclass!r})')
class MyError(Exception,Metaclass=MyMeta):
pass
现在,当引发此类异常时,将调用__subclasscheck__
方法;即raise MyError()
的结果是:
__subclasscheck__(<class '__main__.MyError'>,<class '__main__.MyError'>)
Traceback (most recent call last):
File "test.py",line 8,in <module>
raise MyError()
__main__.MyError
在这里,输出的第一行显示__subclasscheck__
被调用来检查MyError
是否是其本身的子类,即issubclass(MyError,MyError)
。我想了解为什么这是必需的,以及它通常如何有用。
我正在使用cpython 3.8.1重现此行为。我还尝试了PyPy3(3.6.9),这里没有调用__subclasscheck__
。
解决方法
我想这是CPython实现的细节。如PyErr_NormalizeException
的文档所述:
在某些情况下,
PyErr_Fetch()
返回的值 下面可以是“未规范化”,这意味着*exc
是一个类对象,但是*val
不是同一类的实例。
因此,在处理引发的错误的某个时候,CPython会将异常规范化,因为否则它无法假定错误的值是正确的类型。
在您的情况下,情况如下:
- 最终,在处理异常时,会
PyErr_Print
_PyErr_NormalizeException
被调用calls。 -
_PyErr_NormaliizeException
callsPyObject_IsSubclass
。 -
PyObject_IsSubclass
使用__subclasscheck__
(如果提供)。
我不能说“ *exc
的那些“某些情况”是一个类对象,但是*val
不是同一类的实例”(为了向后兼容,可能需要-我不知道知道)。
我的第一个假设是,当CPython确保(即here)该异常源自BaseException
时发生。
以下代码
class OldStyle():
pass
raise OldStyle
对于Python2,将会提高OldStyle
,对于{p> 1,则会{1>}
TypeError: exceptions must be old-style classes or derived from BaseException,not type
或class NewStyle(object):
pass
raise NewStyle
在Python3中,因为在Python3中所有类都是“新样式”。
但是,此检查不使用TypeError: exceptions must derive from BaseException
而是使用PyType_FastSubclass
:
PyObject_IsSubclass
即仅查看#define PyExceptionClass_Check(x) \
(PyType_Check((x)) && \
PyType_FastSubclass((PyTypeObject*)(x),Py_TPFLAGS_BASE_EXC_SUBCLASS))
。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。