一直没有搞明白 Exception
的 args 和 message 参数, 最近看了一下 CPython 源码,
终于搞明白了。
一开始(从2.5开始)的时候是有 args
和 message
两个参数的。2.6版本之后,把
message
废弃掉了,只留下了一个任意长度的 args
。
以下是2.5以后的代码,可以看到,如果args 长度是1,就会把 self.message = args[0]
static PyObject *
BaseException_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
PyBaseExceptionObject *self;
self = (PyBaseExceptionObject *)type->tp_alloc(type, 0);
if (!self)
return NULL;
/* the dict is created on the fly in PyObject_GenericSetAttr */
self->message = self->dict = NULL;
self->args = PyTuple_New(0);
if (!self->args) {
Py_DECREF(self);
return NULL;
}
self->message = PyString_FromString("");
if (!self->message) {
Py_DECREF(self);
return NULL;
}
return (PyObject *)self;
}
static int
BaseException_init(PyBaseExceptionObject *self, PyObject *args, PyObject *kwds)
{
if (!_PyArg_NoKeywords(Py_TYPE(self)->tp_name, kwds))
return -1;
Py_DECREF(self->args);
self->args = args;
Py_INCREF(self->args);
if (PyTuple_GET_SIZE(self->args) == 1) {
Py_CLEAR(self->message);
self->message = PyTuple_GET_ITEM(self->args, 0);
Py_INCREF(self->message);
}
return 0;
}
本来 message 就是 Exception的一个属性,在2.6以后,把它变成了一个 descriptor, 当
调用时,如果它在 self.__dict__
里,就直接打印,否则就返回 self.message
的信息
并打印出一个 Warning
。如果已经赋过一个值的话self.message = xxxx
, 它就会存在
self.__dict__
里。
static PyObject *
BaseException_get_message(PyBaseExceptionObject *self)
{
PyObject *msg;
/* if "message" is in self->dict, accessing a user-set message attribute */
if (self->dict &&
(msg = PyDict_GetItemString(self->dict, "message"))) {
Py_INCREF(msg);
return msg;
}
if (self->message == NULL) {
PyErr_SetString(PyExc_AttributeError, "message attribute was deleted");
return NULL;
}
/* accessing the deprecated "builtin" message attribute of Exception */
if (PyErr_WarnEx(PyExc_DeprecationWarning,
"BaseException.message has been deprecated as "
"of Python 2.6", 1) < 0)
return NULL;
Py_INCREF(self->message);
return self->message;
}
static int
BaseException_set_message(PyBaseExceptionObject *self, PyObject *val)
{
/* if val is NULL, delete the message attribute */
if (val == NULL) {
if (self->dict && PyDict_GetItemString(self->dict, "message")) {
if (PyDict_DelItemString(self->dict, "message") < 0)
return -1;
}
Py_XDECREF(self->message);
self->message = NULL;
return 0;
}
/* else set it in __dict__, but may need to create the dict first */
if (self->dict == NULL) {
self->dict = PyDict_New();
if (!self->dict)
return -1;
}
return PyDict_SetItemString(self->dict, "message", val);
}
在 python3 中,message 相关的信息已经完全删除掉了。
所以,一般使用 message
属性的话,推荐这样使用
class MyException(Exception):
def __init__(self, message):
self.message = message
class My2Exception(Exception):
message = 'this is a message'
原始链接:http://xcodest.me/python-exception-init-args.html
许可协议:"署名-非商用-相同方式共享 3.0" 转载请保留原文链接及作者。
Comments