args 被实现为具有__get__ 和__set__ 方法的数据描述符。
这发生在BaseException.__new__ 内部,就像@bakatrouble 提到的那样。除此之外,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
在Python 3.7.0 alpha 1的 C 代码中,上面的 Python 代码如下所示(检查 Python 的 C 代码是否存在过去或未来的差异): p>
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
}
交互式实验:
>>> e = Exception('aaa')
>>> e
Exception('aaa',)
>>> BaseException.args.__set__(e, ('bbb',))
>>> e
Exception('bbb',)
>>> BaseException.args.__get__(e)
('bbb',)
因此,args 的神奇灵感让你的眼睛看起来像天堂一样发生在BaseException.__new__ 中,当BaseException 或其任何子类的对象被创建时。