Python 异常 - 如何自动设置 args 属性?

deb*_*ish 6 python exception python-3.x

假设我定义了以下异常:

>>> class MyError(Exception):
...     def __init__(self, arg1):
...         pass
Run Code Online (Sandbox Code Playgroud)

然后我实例化该类以创建一个异常对象:

>>> e = MyError('abc')
>>> e.args
('abc',)
Run Code Online (Sandbox Code Playgroud)

这里的args属性是如何设置的?(在 中__init__,我什么都不做。)

dir*_*obs 9

args__get__使用和方法作为数据描述符实现__set__。

就像 @bakatrouble 提到的那样,这发生在内部BaseException.__new__。除此之外,内部发生的事情BaseException.__new__大致类似于下面的Python代码:

class BaseException:
    def __new__(cls, *args): 
        # self = create object of type cls
        self.args = args  # This calls: BaseException.args.__set__(self, args) 
        ...
        return self
Run Code Online (Sandbox Code Playgroud)

在Python 3.7.0 alpha 1的 C 代码中,上面的 Python 代码如下所示(检查 Python 的 C 代码是否有任何过去或未来的差异):

BaseException_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
    # other things omitted... 
    self = (PyBaseExceptionObject *)type->tp_alloc(type, 0);
    # many things follow... 
    if (args) {
        self->args = args;
        Py_INCREF(args);
        return (PyObject *)self;

    }
    # many more things follow
}
Run Code Online (Sandbox Code Playgroud)

交互实验:

>>> e = Exception('aaa')
>>> e
Exception('aaa',)
Run Code Online (Sandbox Code Playgroud)
>>> BaseException.args.__set__(e, ('bbb',))
>>> e
Exception('bbb',)
>>> BaseException.args.__get__(e)
('bbb',)
Run Code Online (Sandbox Code Playgroud)

因此,当创建它的一个对象或其任何子类时,就会产生神奇的灵感,args让你的眼睛望向天堂。BaseException.__new__BaseException


bak*_*ble 1

它是在方法中设置的BaseException.__new__(),可以在这里看到:源代码

注意:在 Python 2.7 中,它是在方法中设置的BaseException.__init__(),因此覆盖使.argsdict 始终为空(不确定是否指向正确的行):源代码