将关键字参数传递给自定义异常 - 异常

时间:2015-06-10 01:39:59

标签: python exception keyword-argument

为什么我会在以下两个代码段(Python 3.4)中获得不同的结果:

class MainError(Exception):
    def __init__(self, msg, **parms):
        super().__init__()  
        self.msg = msg
        self.parms = parms
        print('Parms original', parms)

    def __str__(self):
        return self.msg + ':' + str(self.parms)

class SubError(MainError):
    def __init__(self, msg, **parms):
        super().__init__(msg, **parms)

try:
    raise SubError('Error occured', line = 22, col = 11)
except MainError as e:
    print(e)


>>> 
Parms original {'line': 22, 'col': 11}
Error occured:{'line': 22, 'col': 11}

class MainError(Exception):
    def __init__(self, msg, **args):
        super().__init__()  
        self.msg = msg
        self.args = args
        print('Parms original', args)

    def __str__(self):
        return self.msg + ':' + str(self.args)

class SubError(MainError):
    def __init__(self, msg, **args):
        super().__init__(msg, **args)

try:
    raise SubError('Error occured', line = 22, col = 11)
except MainError as e:
    print(e)


>>> 
Parms original {'line': 22, 'col': 11}
Error occured:('line', 'col')

1 个答案:

答案 0 :(得分:2)

这是因为错误args被覆盖,通过将它们转换为C级别的Python元组。

这是Python的BaseException类: https://hg.python.org/cpython/file/tip/Objects/exceptions.c

从第31行开始,我们看到以下内容:

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->dict = NULL;
    self->traceback = self->cause = self->context = NULL;
    self->suppress_context = 0;

    if (args) {
        self->args = args;
        Py_INCREF(args);
        return (PyObject *)self;
    }

    self->args = PyTuple_New(0);
    if (!self->args) {
        Py_DECREF(self);
        return NULL;
    }

    return (PyObject *)self;
}

同样,init调用具有相同的元组转换:

BaseException_init(PyBaseExceptionObject *self, PyObject *args, PyObject *kwds)
{
    PyObject *tmp;

    if (!_PyArg_NoKeywords(Py_TYPE(self)->tp_name, kwds))
        return -1;

    tmp = self->args;
    self->args = args;
    Py_INCREF(self->args);
    Py_XDECREF(tmp);

    return 0;
}

简而言之,self.args正在转换为元组,并将其转换回字符串,从而产生差异。

为所有方法包装器调用BaseException类(我相信)作为必需参数。

如果传递一个不可迭代的参数(例如整数),这是很明显的:

>>> class CustomException(Exception):
...     def __init__(self):
...         super(CustomException, self).__init__('a')
...         self.args = 1
...     def __repr__(self):
...         print(self.args)
...         return ''
... 
>>> CustomException()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 4, in __init__
TypeError: 'int' object is not iterable

故事的道德:不要将您的变量命名为经常重新定义的词,并且是您正在使用的课程的关键术语。