2015-06-10 39 views
2

爲什麼我得到以下兩個代碼段不同的結果(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') 

回答

2

這是因爲錯誤ARG遊戲通過將它們轉換爲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; 
} 

同樣,初始化調用具有相同的元組的轉換:

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 

這個故事的寓意:不要名稱都在不斷重新定義和對於關鍵術語的變量的話你正在使用的課程。