话说今天青蛙遇到了一个bug,在某个Exception里抛出了TypeError Exception, 青蛙仔细查了半天,才想到Exception有一个内置属性args,刚好跟这个Exception 定义中的args重名。
首先看下这个Exception的定义:
In [4]: class E(Exception):
def __init__(self, a, b, c):
Exception.__init__(self)
self.a = a
self.args = b
self.c = c
def __str__(self):
return "a = %r, b = %r, c = %r" % (self.a, self.args, self.c)
....:
当这个Exception被触发时,又引发了一个TypeError:
In [5]: raise E('1', None, '3')
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-6-b57acf162917> in <module>()
----> 1 raise E('1', None, '3')
<ipython-input-5-fac85dd51acb> in __init__(self, a, b, c)
2 def __init__(self, a, b, c):
3 Exception.__init__(self)
4 self.a = a
----> 5 self.args = b
6 self.c = c
7 def __str__(self):
TypeError: 'NoneType' object is not iterable
这就是Exception的args属性在作怪了,如果把self.args的名字换一下,世界又恢复正常了。
In [2]: class E(Exception):
def __init__(self, a, b, c):
Exception.__init__(self)
self.a = a
self.b = b
self.c = c
def __str__(self):
return "a = %r, b = %r, c = %r" % (self.a, self.b, self.c)
....:
In [3]: raise E('1', None, '3')
---------------------------------------------------------------------------
E Traceback (most recent call last)
<ipython-input-3-b57acf162917> in <module>()
----> 1 raise E('1', None, '3')
E: a = '1', b = None, c = '3'
背后的原因呢,就是Python不管这个args是啥,都会转换成一个tuple, 但是当args是一个NoneType,问题就来了。
17 /*
18 * BaseException
19 */
20 static PyObject *
21 BaseException_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
22 {
23 PyBaseExceptionObject *self;
24
25 self = (PyBaseExceptionObject *)type->tp_alloc(type, 0);
26 if (!self)
27 return NULL;
28 /* the dict is created on the fly in PyObject_GenericSetAttr */
29 self->dict = NULL;
30 self->traceback = self->cause = self->context = NULL;
31
32 self->args = PyTuple_New(0);
33 if (!self->args) {
34 Py_DECREF(self);
35 return NULL;
36 }
37
38 return (PyObject *)self;
39 }
找到原因,解决起来就很简单了。给args换个名字,一切ok。 当然编码时的坏习惯才是导致这种bug最大的根源,以后千万不能乱写变量名了。
Comments
comments powered by Disqus