在Python C扩展中引发类型错误时获取PyObjectType的字符串表示形式
我正在检查用户输入的类型,如下所示:在Python C扩展中引发类型错误时获取PyObjectType的字符串表示形式,python,python-2.7,python-c-api,python-c-extension,Python,Python 2.7,Python C Api,Python C Extension,我正在检查用户输入的类型,如下所示: 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) {
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;
}
你可以稍微误用一下。稍微有点不整洁的是,它输出为常量char*
,因此您也必须从元组中获取该项
const char* out;
if (!PyArg_ParseTuple(tpl,"s", &out)) {
return NULL;
} else {
key = PyTuple_GetItem(tpl,0); /* borrowed - remember to incref */
}
这会产生类似于
TypeError:必须是str,而不是int
注意:这对于Python2很好,因为
“s”
同时匹配str
或unicode
对象(即有效地基串
)。对于Python3,它只接受str
(而不是bytes
),因此您可能必须遵循和“将O&
格式与PyUnicode\u FSConverter()
一起用作转换器”。这会导致以下错误:
TypeError:无法将“int”对象隐式转换为str
此外,它还有一点更好,因为
out
是一个PyBytesObject
,您可以直接使用它,而不必执行PyTuple\u GetItem
抱歉造成混淆;我的意思是要求一个通用的解决方案,可以应用于任何PyObject,而不一定是tuple。然而,你让我思考,为什么不继续这样做:PyArg\u ParseTuple(Py\u BuildValue(“(o)”,“s”,&out))
-你认为呢?我认为(但我不是100%确定)可以接受一个元组或一个参数(基于它设计用于的旧函数调用方法的描述)。我还没有测试过这个