日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > python >内容正文

python

python 异常处理模块_扩展Python模块系列(五)----异常和错误处理

發(fā)布時間:2023/12/9 python 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 python 异常处理模块_扩展Python模块系列(五)----异常和错误处理 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

在上一節(jié)中,討論了在用C語言擴展Python模塊時,應(yīng)該如何處理無處不在的引用計數(shù)問題。重點關(guān)注的是在實現(xiàn)一個C Python的函數(shù)時,對于一個PyObject對象,何時調(diào)用Py_INCREF和Py_DECREF。在編寫C語言代碼時,需要了解Python提供的C/C++ API的實現(xiàn)細節(jié),特別是有的API內(nèi)部實現(xiàn)會調(diào)用Py_INCREF,這時自己編寫的函數(shù)可能需要調(diào)用Py_DECREF,而有的API內(nèi)部實現(xiàn)只是borrowed reference,此時一般不應(yīng)該調(diào)用Py_DECREF。

本節(jié)討論在C擴展Python時,如何對異常和錯誤進行處理。Python解釋器的實現(xiàn)中有一個重要的約定:當(dāng)一個函數(shù)失敗,它應(yīng)該設(shè)置一個exception condition并返回一個錯誤值(通常是NULl指針)。異常是存放在解釋器的一個全局變量中,如果這個變量是NULL,那么沒有異常發(fā)生。另外一個全局變量存放的是跟異常相關(guān)的值,還有一個變量包含了stack traceback,記錄了產(chǎn)生錯誤時的Python Code。這三個變量對應(yīng)Python的sys模塊的三個變量,sys.exc_type, sys.exc_value, sys.exc_traceback。在1.5版本之后,這三個變量用exc_info()代替了。

這三個全局的變量在C Python 源碼中是存放在PyThreadState *_PyThreadState_Current這個結(jié)構(gòu)體中的, 而_PyThreadState_Current是在pythonrun.c的Py_InitializeEx中初始化的。

PyThreadState結(jié)構(gòu)體定義:

紅色框中的三個變量就是error indicator。

常見的Python設(shè)置異常的接口

Python API定義了一系列的function來設(shè)置不同類型的異常,定義在Python源碼中的Python/error.c中。

PyErr_SetString:

最常用的莫過于PyErr_SetString,函數(shù)的原型為:

函數(shù)的作用是設(shè)置Python解釋器的全局error indicator。

參數(shù)分別為一個exception對象和一個描述異常的字符串。exception object通常是一個已經(jīng)定義好的object, 不需要增加它的引用計數(shù),在PyErr_SetString源碼中已經(jīng)調(diào)用了Py_XINCREF(exception)。

/*Predefined exceptions*/PyAPI_DATA(PyObject*) PyExc_BaseException;

PyAPI_DATA(PyObject*) PyExc_Exception;

PyAPI_DATA(PyObject*) PyExc_StopIteration;

PyAPI_DATA(PyObject*) PyExc_GeneratorExit;

PyAPI_DATA(PyObject*) PyExc_StandardError;

PyAPI_DATA(PyObject*) PyExc_ArithmeticError;

PyAPI_DATA(PyObject*) PyExc_LookupError;

PyAPI_DATA(PyObject*) PyExc_AssertionError;

PyAPI_DATA(PyObject*) PyExc_AttributeError;

PyAPI_DATA(PyObject*) PyExc_EOFError;

PyAPI_DATA(PyObject*) PyExc_FloatingPointError;

PyAPI_DATA(PyObject*) PyExc_EnvironmentError;

PyAPI_DATA(PyObject*) PyExc_IOError;

PyAPI_DATA(PyObject*) PyExc_OSError;

PyAPI_DATA(PyObject*) PyExc_ImportError;

PyAPI_DATA(PyObject*) PyExc_IndexError;

PyAPI_DATA(PyObject*) PyExc_KeyError;

PyAPI_DATA(PyObject*) PyExc_KeyboardInterrupt;

PyAPI_DATA(PyObject*) PyExc_MemoryError;

PyAPI_DATA(PyObject*) PyExc_NameError;

PyAPI_DATA(PyObject*) PyExc_OverflowError;

PyAPI_DATA(PyObject*) PyExc_RuntimeError;

PyAPI_DATA(PyObject*) PyExc_NotImplementedError;

PyAPI_DATA(PyObject*) PyExc_SyntaxError;

PyAPI_DATA(PyObject*) PyExc_IndentationError;

PyAPI_DATA(PyObject*) PyExc_TabError;

PyAPI_DATA(PyObject*) PyExc_ReferenceError;

PyAPI_DATA(PyObject*) PyExc_SystemError;

PyAPI_DATA(PyObject*) PyExc_SystemExit;

PyAPI_DATA(PyObject*) PyExc_TypeError;

PyAPI_DATA(PyObject*) PyExc_UnboundLocalError;

PyAPI_DATA(PyObject*) PyExc_UnicodeError;

PyAPI_DATA(PyObject*) PyExc_UnicodeEncodeError;

PyAPI_DATA(PyObject*) PyExc_UnicodeDecodeError;

PyAPI_DATA(PyObject*) PyExc_UnicodeTranslateError;

PyAPI_DATA(PyObject*) PyExc_ValueError;

PyAPI_DATA(PyObject*) PyExc_ZeroDivisionError;

PyErr_SetObject:

從PyErr_SetString實現(xiàn)的源碼中可以看到,內(nèi)部調(diào)用了PyErr_SetObject, PyErr_SetObject內(nèi)部又調(diào)用了PyErr_Restore。

PyErr_SetObject函數(shù)原型是:

PyObject* PyErr_Occurred():

函數(shù)返回當(dāng)前是否有異常發(fā)生,如果有返回current exception object【borrowed reference】,否則返回NULL

int PyErr_ExceptionMatches(PyObject* exc)

int PyErr_GivenExceptionMatches(PyObject* given, PyObject* exc):

判斷給定的異常對象是否符合exc類型。

PyErr_Clear():

清除Python解釋器的error indicator。Python解釋器不會檢測到有異常發(fā)生。

PyErr_Fetch(PyObject** ptype, PyObject** pvalue, PyObject** ptraceback)

獲得error indicator的三個變量,如果error indicator沒有設(shè)置,ptype, pvalue, ptraceback都被設(shè)置為NULL。error indicator會被置空,將三個變量的地址賦給ptype, pvalue, ptraceback。

PyErr_Restore(PyObject* type, PyObject* value, PyObject* traceback)

使用給定的三個變量設(shè)置error indicator。

代碼中使用異常接口的規(guī)則

如果函數(shù)f調(diào)用函數(shù)g,其中g(shù)函數(shù)失敗,應(yīng)該怎樣設(shè)置異常呢?通常的做法是在g中調(diào)用設(shè)置異常的各個接口,比如PyErr_SetString,通知Python解釋器有異常發(fā)生了,函數(shù)g然后返回一個NULL給函數(shù)f,而f不用再處理異常,因為函數(shù)g已經(jīng)上報過了。比如我們自己寫的函數(shù)調(diào)用了PyArg_ParseTuple(),這個函數(shù)出現(xiàn)錯誤時返回NULL,但是我們不用自己上報異常,異常的上報由PyArg_ParseTuple本身處理。一旦通過PyErr_SetString設(shè)置了異常,那么Python解釋器在主循環(huán)中檢測到error indicator被設(shè)置,會暫停執(zhí)行當(dāng)前的Python Code,會試圖尋找exception handler來處理異常。

Python源碼中使用異常處理接口的例子

PyTuple_GetItem:

PyObject *PyTuple_GetItem(register PyObject*op, register Py_ssize_t i)

{if (!PyTuple_Check(op)) {

PyErr_BadInternalCall();returnNULL;

}if (i < 0 || i >=Py_SIZE(op)) {//如果索引有錯誤,設(shè)置異常

PyErr_SetString(PyExc_IndexError, "tuple index out of range");returnNULL;

}return ((PyTupleObject *)op) ->ob_item[i];

}

PyErr_SetString實現(xiàn):

voidPyErr_SetString(PyObject*exception, const char *string)

{

PyObject*value = PyString_FromString(string);

PyErr_SetObject(exception, value);

Py_XDECREF(value);

}

PyErr_SetObject實現(xiàn):

voidPyErr_SetObject(PyObject*exception, PyObject *value)

{

Py_XINCREF(exception);//增加引用計數(shù)

Py_XINCREF(value); //增加引用計數(shù)

PyErr_Restore(exception, value, (PyObject *)NULL);

}

PyErr_Restore實現(xiàn):

voidPyErr_Restore(PyObject*type, PyObject *value, PyObject *traceback)

{

PyThreadState*tstate =PyThreadState_GET();

PyObject*oldtype, *oldvalue, *oldtraceback;if (traceback != NULL && !PyTraceBack_Check(traceback)) {/*XXX Should never happen -- fatal error instead?*/

/*Well, it could be None.*/Py_DECREF(traceback);

traceback=NULL;

}/*Save these in locals to safeguard against recursive

invocation through Py_XDECREF*/oldtype= tstate->curexc_type;

oldvalue= tstate->curexc_value;

oldtraceback= tstate->curexc_traceback;//設(shè)置當(dāng)前的異常

tstate->curexc_type =type;

tstate->curexc_value =value;

tstate->curexc_traceback =traceback;//舊的異常變量需要減少引用計數(shù)

Py_XDECREF(oldtype);

Py_XDECREF(oldvalue);

Py_XDECREF(oldtraceback);

}

自定義異常

除了使用Python已經(jīng)定義好的異常對象之外,我們可以自定義異常類型,主要是通過PyErr_NewException創(chuàng)建一個異常對象。

1. 在文件頭部定義一個static 變量:

static PyObject *MyError;

2. 在模塊初始化時傳入我們自定義的異常對象

PyMODINIT_FUNC

inittest(void)

{

PyObject*m;

m= Py_InitModule("test", TestMethods);if (m ==NULL)return;

MyError= PyErr_NewException("test.error", NULL, NULL);

Py_INCREF(MyError);

PyModule_AddObject(m,"error",MyError);

}

3. 在通過PyErr_SetString設(shè)置異常時,第一個參數(shù)傳入MyError即可。

總結(jié)

以上是生活随笔為你收集整理的python 异常处理模块_扩展Python模块系列(五)----异常和错误处理的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。