python - 如何在 CPython 模块的 init 方法中引发异常

标签 python python-2.7 cpython python-internals

我正在写一个 CPythonC 中编写的库之上的扩展我找不到关于如何在 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 doc,如果你想让解释器引发异常,你需要调用用于引发异常的方法之一,在我的例子中我使用 PyErr_SetString(PyExc_ValueError, msgError) , 并返回 null .

在本例中是 CPython 中的 init 方法必须是 static int ,所以我不能返回 null ,但是,我确实删除了 return语句,我在 stdout 中看到了异常,但翻译并没有停下来。

我怎样才能做到这一点?

最佳答案

你应该在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 中,如果发生错误,则返回 -1 而不是 null 来发出信号。

关于python - 如何在 CPython 模块的 init 方法中引发异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38439988/

相关文章:

带有正则表达式的 Python 3.7 : Why can I no longer substitute with a string containing a backslash (\)?

python - virtualenv : ERROR - Failed to load fernet while encrypting value 上的 apache Airflow

python - 什么是 co_names?

python - cPython 是否使用多个内核来实现排序、任意、全部等内置函数?

python - 为什么 CPython 预分配一些整数?

python - 如何在 TravisCI 上添加 NLTK 'wordnet' ?

python - 如何在Python中通过Flask传递内存中的Azure Blob

python - 覆盖/溺爱的优化(覆盖__getattribute__/__getattr__)

python - 根据列 value_counts (pandas) 过滤数据框

Python同时迭代两个列表