如何在 CPython 模块的 init 方法中引发异常
How to raise an exception in the init method for a CPython module
我正在 C
中编写的库之上编写一个 CPython
扩展,但我找不到关于如何在 init
中引发异常的解决方案方法。所以,我把它分开了,基本上,构造函数会将属性保存到对象中,然后你必须调用一个 init 方法 mr.initialize()
.
我觉得这个方法有点难看,我想找到一个在构造函数中引发 ValueError
异常的解决方案,这是我当前的代码:
static int libzihc_MRLoader_init(libzihc_MRLoader *self, PyObject *args, PyObject *kwds) {
double error_rate;
const char *in;
unsigned int capacity;
static char *kwlist[] = {"in", NULL};
if (!PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist, &in)) {
return -1;
}
if (self->dataPath) {
free(self->dataPath);
}
self->dataPath = malloc(sizeof(char)*(strlen(in)+1));
if (self->dataPath) {
strcpy(self->dataPath, in);
} else {
PyErr_NoMemory();
}
return 0;
}
并且添加的初始化方法如下:
static PyObject* initialize(libzihc_MRLoader *self, PyObject *args, PyObject *kwds) {
const char * msgError = NULL;
int status = openRes(self->dataPath, &(self->ienaKey), &msgError);
if(status != 0) {
PyErr_SetString(PyExc_ValueError, msgError);
printf("openRes returns %d\n", status);
return (PyObject *) NULL;
}
return Py_BuildValue("i", status);
}
从 CPython
文档中,如果您希望解释器引发异常,您需要调用一种用于引发异常的方法,在我的例子中我使用 PyErr_SetString(PyExc_ValueError, msgError)
,并且 return null
.
在这种情况下,CPython
中的 init 方法必须是 static int
,所以我不能 return null
,但是我删除了 [=23] =]语句,我在stdout
中看到了异常,但是解释器并没有停止。
我怎样才能做到这一点?
你应该return一个负值在libzihc_MRLoader_init
,通常-1
为了Python捕获它,搜索是否设置了异常并结束执行。至少,这就是 type_call
在调用对象 __init__
方法后检查的内容:
type = obj->ob_type;
if (PyType_HasFeature(type, Py_TPFLAGS_HAVE_CLASS) &&
type->tp_init != NULL &&
type->tp_init(obj, args, kwds) < 0) { // if res < 0 returns NULL
Py_DECREF(obj);
obj = NULL;
}
因此,在您的特定情况下,您可以将代码从 initialize
移动到 libzihc_MRLoader_init
,如果发生错误,return -1
而不是 null
发出信号。
我正在 C
中编写的库之上编写一个 CPython
扩展,但我找不到关于如何在 init
中引发异常的解决方案方法。所以,我把它分开了,基本上,构造函数会将属性保存到对象中,然后你必须调用一个 init 方法 mr.initialize()
.
我觉得这个方法有点难看,我想找到一个在构造函数中引发 ValueError
异常的解决方案,这是我当前的代码:
static int libzihc_MRLoader_init(libzihc_MRLoader *self, PyObject *args, PyObject *kwds) {
double error_rate;
const char *in;
unsigned int capacity;
static char *kwlist[] = {"in", NULL};
if (!PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist, &in)) {
return -1;
}
if (self->dataPath) {
free(self->dataPath);
}
self->dataPath = malloc(sizeof(char)*(strlen(in)+1));
if (self->dataPath) {
strcpy(self->dataPath, in);
} else {
PyErr_NoMemory();
}
return 0;
}
并且添加的初始化方法如下:
static PyObject* initialize(libzihc_MRLoader *self, PyObject *args, PyObject *kwds) {
const char * msgError = NULL;
int status = openRes(self->dataPath, &(self->ienaKey), &msgError);
if(status != 0) {
PyErr_SetString(PyExc_ValueError, msgError);
printf("openRes returns %d\n", status);
return (PyObject *) NULL;
}
return Py_BuildValue("i", status);
}
从 CPython
文档中,如果您希望解释器引发异常,您需要调用一种用于引发异常的方法,在我的例子中我使用 PyErr_SetString(PyExc_ValueError, msgError)
,并且 return null
.
在这种情况下,CPython
中的 init 方法必须是 static int
,所以我不能 return null
,但是我删除了 [=23] =]语句,我在stdout
中看到了异常,但是解释器并没有停止。
我怎样才能做到这一点?
你应该return一个负值在libzihc_MRLoader_init
,通常-1
为了Python捕获它,搜索是否设置了异常并结束执行。至少,这就是 type_call
在调用对象 __init__
方法后检查的内容:
type = obj->ob_type;
if (PyType_HasFeature(type, Py_TPFLAGS_HAVE_CLASS) &&
type->tp_init != NULL &&
type->tp_init(obj, args, kwds) < 0) { // if res < 0 returns NULL
Py_DECREF(obj);
obj = NULL;
}
因此,在您的特定情况下,您可以将代码从 initialize
移动到 libzihc_MRLoader_init
,如果发生错误,return -1
而不是 null
发出信号。