首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >为什么引发异常会调用__subclasscheck__?

为什么引发异常会调用__subclasscheck__?
EN

Stack Overflow用户
提问于 2020-09-16 21:46:09
回答 1查看 200关注 0票数 4

考虑以下使用__subclasscheck__作为自定义异常类型的示例:

代码语言:javascript
复制
class MyMeta(type):
    def __subclasscheck__(self, subclass):
        print(f'__subclasscheck__({self!r}, {subclass!r})')

class MyError(Exception, metaclass=MyMeta):
    pass

现在,当引发此类型的异常时,将调用__subclasscheck__方法;即,raise MyError()将导致:

代码语言:javascript
复制
__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__

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-09-21 06:27:59

我想这是一个CPython实现细节。如PyErr_NormalizeException文档中所述

在某些情况下,下面PyErr_Fetch()返回的值可能是“未规范化的”,这意味着*exc是类对象,但*val不是同一个类的实例。

因此,在处理引发的错误时,CPython会将异常规范化,因为否则它不能假定错误的值是正确的类型。

就您的情况而言,情况如下:

  • 最终,在处理异常时,会调用PyErr_Print,其中它是呼叫 _PyErr_NormalizeException
  • _PyErr_NormaliizeException 呼叫 PyObject_IsSubclass.
  • 如果提供PyObject_IsSubclass,则使用__subclasscheck__

我不能说"*exc是类对象,但*val不是同一个类的实例“的”特定情况“是什么(可能是向后兼容性所需要的--我不知道)。

我的第一个假设是,当CPython确保(即这里)异常来自BaseException时,就会发生这种情况。

以下代码

代码语言:javascript
复制
class OldStyle():
    pass

raise OldStyle

将为OldStyle为Python2,而TypeError: exceptions must be old-style classes or derived from BaseException, not type

代码语言:javascript
复制
class NewStyle(object):
    pass

raise NewStyle

或者在TypeError: exceptions must derive from BaseException中使用Python3,因为在Python3中所有类都是“新样式”。

但是,对于此检查,使用的不是PyObject_IsSubclass,而是PyType_FastSubclass

代码语言:javascript
复制
#define PyExceptionClass_Check(x)                                       \
    (PyType_Check((x)) &&                                               \
     PyType_FastSubclass((PyTypeObject*)(x), Py_TPFLAGS_BASE_EXC_SUBCLASS))

也就是说,只查看tpflags。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/63928368

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档