2017-02-12 13 views
0

我檢查的類型的用戶輸入,像這樣獲得一個PyObjectType的字符串表示:在Pythonç提高時類型錯誤擴展

PyObject *key = PyTuple_GetItem(tuple, 0); 
if (!PyObject_TypeCheck(key, &PyBaseString_Type) { 
    PyErr_SetString(PyExc_TypeError, "Key must be str"); 
    return NULL; 
} 

然而,在異常消息,我想包括用戶提交的錯誤類型,使他更容易調試。

有沒有簡單或其他地道的方法來實現這一目標?


我能想到的唯一的辦法是:

PyObject *key = PyTuple_GetItem(tuple, 0); 
if (!PyObject_TypeCheck(key, &PyBaseString_Type) { 
    // This returns a new reference which must be Py_DECREFed 
    PyObject *bad_type_string = PyObject_Str((PyObject *)key->ob_type); 
    char *bad_type_char = PyString_AsString(bad_type_string); 
    PyErr_Format(PyExc_TypeError, "Key must be str, not %s", bad_type_char); 
    Py_DECREF(bad_type_string); 
    return NULL; 
} 

這一點我想我可以在一個宏包:

# define CHECK_TYPE(expr, name, input) \ 
    do { \ 
     if (!(expr)) { 
      PyObject *bad_type_string = PyObject_Str((PyObject *)input->ob_type); \ 
      char *bad_type_char = PyString_AsString(bad_type_string); \ 
      PyErr_Format(PyExc_TypeError, "%s must be str, not %s", name bad_type_char); \ 
      Py_DECREF(bad_type_string); \ 
      goto error; \ 
     } 
    } while (0); 

而像這樣使用:

static PyObject *foo(PyObject *self, PyObject *args) { 
    // ... 
    PyObject *key = PyTuple_GetItem(tuple, 0); 
    CHECK_TYPE(PyObject_TypeCheck(key, &PyBaseString_Type, 'key', key); 
    // ... 
error: 
    return NULL; 
} 

回答

0

你可能會輕微誤用the PyArg_ParseTuple mechanism。非巧妙的一點是它輸出到const char*,所以你必須從元組中獲取項目。

const char* out; 
if (!PyArg_ParseTuple(tpl,"s", &out)) { 
    return NULL; 
} else { 
    key = PyTuple_GetItem(tpl,0); /* borrowed - remember to incref */ 
} 

這產生類似

TypeError: must be str, not int


注意:這是細的Python 2,因爲既"s"str對象unicode(即有效basestring)匹配。對於Python 3,它只接受str(而不是bytes),因此您可能需要按照the documented advice和「」的格式使用PyUnicode_FSConverter()作爲轉換器。這給出了

TypeError: Can't convert 'int' object to str implicitly

另外一個錯誤,這是一個更好一點,因爲out是一個PyBytesObject,你可以直接使用,而不必做PyTuple_GetItem

+0

很抱歉的混亂;我的意思是要求可以應用於任何PyObject的通用解決方案,而不一定是元組。然而,你讓我想,爲什麼不繼續這樣下去:'PyArg_ParseTuple(Py_BuildValue(「(o)」,「s」,&out))' - 你怎麼看? –

+0

我認爲(但我不是100%肯定)['PyArg_Parse'](https://docs.python.org/2/c-api/arg.html#c.PyArg_Parse)可以採用元組或者一個參數(基於它被設計使用的舊函數調用方法的描述)。我還沒有測試過 – DavidW