python 異常處理模塊_擴展Python模塊系列(五)----異常和錯誤處理

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

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

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

PyThreadState結構體定義:

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

常見的Python設置異常的接口

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

PyErr_SetString:

最常用的莫過于PyErr_SetString,函數的原型為:

函數的作用是設置Python解釋器的全局error indicator。

參數分別為一個exception對象和一個描述異常的字符串。exception object通常是一個已經定義好的object, 不需要增加它的引用計數,在PyErr_SetString源碼中已經調用了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實現的源碼中可以看到,內部調用了PyErr_SetObject, PyErr_SetObject內部又調用了PyErr_Restore。

PyErr_SetObject函數原型是:

PyObject* PyErr_Occurred():

函數返回當前是否有異常發生,如果有返回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解釋器不會檢測到有異常發生。

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

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

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

使用給定的三個變量設置error indicator。

代碼中使用異常接口的規則

如果函數f調用函數g,其中g函數失敗,應該怎樣設置異常呢?通常的做法是在g中調用設置異常的各個接口,比如PyErr_SetString,通知Python解釋器有異常發生了,函數g然后返回一個NULL給函數f,而f不用再處理異常,因為函數g已經上報過了。比如我們自己寫的函數調用了PyArg_ParseTuple(),這個函數出現錯誤時返回NULL,但是我們不用自己上報異常,異常的上報由PyArg_ParseTuple本身處理。一旦通過PyErr_SetString設置了異常,那么Python解釋器在主循環中檢測到error indicator被設置,會暫停執行當前的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)) {//如果索引有錯誤,設置異常

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

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

}

PyErr_SetString實現:

voidPyErr_SetString(PyObject*exception, const char *string)

{

PyObject*value = PyString_FromString(string);

PyErr_SetObject(exception, value);

Py_XDECREF(value);

}

PyErr_SetObject實現:

voidPyErr_SetObject(PyObject*exception, PyObject *value)

{

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

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

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

}

PyErr_Restore實現:

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;//設置當前的異常

tstate->curexc_type =type;

tstate->curexc_value =value;

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

Py_XDECREF(oldtype);

Py_XDECREF(oldvalue);

Py_XDECREF(oldtraceback);

}

自定義異常

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

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設置異常時,第一個參數傳入MyError即可。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/276236.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/276236.shtml
英文地址,請注明出處:http://en.pswp.cn/news/276236.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

常見的php筆試題(附答案)搜集整理

轉載鏈接&#xff1a;http://www.yaojinbu.com/p/139.html 常見的php筆試題&#xff08;附答案&#xff09;搜集整理 1.在PHP中&#xff0c;當前腳本的名稱&#xff08;不包括路徑和查詢字符串&#xff09;記錄在哪個預定義變量中&#xff1f;而鏈接到當前頁面的URL又記錄在哪個…

Js整理備忘(02)——運算符

1、運算符的表示以及優先級 Javascript&#xff08;以下簡寫為Js&#xff09;的大部分運算符與C或Java是類似的。 記得剛學C語言時老師講的優先級口訣&#xff0c;非常好記&#xff1a;“括、單、算、移、關”“位、邏、條、賦、逗”&#xff0c;此處也可以套用一下&#xff0c…

手寫一個合格的前端腳手架

為什么我們需要一套腳手架為什么我們需要一套腳手架&#xff0c;它能幫助我們解決哪些痛點問題。?前端項目配置越來越繁瑣、耗時&#xff0c;重復無意義的工作?項目結構不統一、不規范?前端項目類型繁多&#xff0c;不同項目不同配置&#xff0c;管理成本高?腳手架也可以是…

第一篇cnblog!

本人才疏學淺&#xff0c;終于通過了cnblog的審核&#xff0c;興奮之余&#xff0c;發表感言——不容易啊&#xff01;在我的博聞里面&#xff0c;隨筆類當然就是技術類的比較多的&#xff0c;特別是實例類的。理論類的大部分放在文章板塊&#xff0c;本人e文特別好(哈哈&#…

解決error 1045: Access denied for user: 'root@localhost' (Using password: YES)

轉載連接&#xff1a;http://jianfw2009.blog.163.com/blog/static/13431366020111016112459158/ 1、先停止mysql服務2、在mysql的目錄下找到my.ini&#xff0c;在[mysqld]后面加上skip-grant-tables3、啟動mysql服務,打開Command Line Client以空密碼登錄4、退出mysql,并停止服…

fillcolor是什么意思_fill是什么意思

1. (使)裝滿;(使)注滿;(使)充滿If you fill a container or area, or if it fills, an amount of something enters it that is enough to make it full.e.g.Fill a saucepan with water and bring to a slow boil...往平底鍋里加滿水,小火煮沸。e.g.She made sandwiches, fill…

利用JMeter進行壓力測試(1)(轉)

轉自&#xff1a;http://www.cnblogs.com/game-over/archive/2010/01/08/1642685.html壓力測試以軟件響應速度為測試目標&#xff0c;尤其是在較短時間內大量并發用戶的同時訪問時&#xff0c;軟件的性能和抗壓能力。 JMeter是一款開源的壓力測試工具&#xff0c;目前最新Rele…

MyISAM InnoDB 區別

轉載鏈接&#xff1a;http://www.php100.com/html/webkaifa/database/Mysql/2011/0326/7789.html MyISAM 和 InnoDB 講解 InnoDB和MyISAM是許多人在使用MySQL時最常用的兩個表類型&#xff0c;這兩個表類型各有優劣&#xff0c;視具體應用而定。基本的差別為&#xff1a;MyISAM…

Git 內部原理圖解——對象、分支以及如何從零開始建倉庫

我們中的許多人每天都在使用 git&#xff0c;但是有多少人知道它的內部是怎么運作的呢&#xff1f;例如我們使用 git commit 時發生了什么&#xff1f;提交&#xff08;commit&#xff09;與提交之間保存的是什么&#xff1f;兩次提交之間難道只是文件的差異&#xff08;dif…

wpsmac和pc版的區別_Mac版WPS Office和微軟Office 2019哪個更好?

眾所周知&#xff0c; macOS系統生態下&#xff0c;有許多界面精美、功能強大、體驗出色的軟件&#xff0c;但提到辦公套件&#xff0c;人們首先想到的還是微軟 Office 套件&#xff0c;其中的Word、 Excel 以及PPT&#xff0c;但用戶體驗并不如意。但現在&#xff0c;蘋果用戶…

A tutorial video for MindManager for free

MindManager 2016 for Windows Essential Training 本人學習的時候使用的是MindManager 2018版本的&#xff0c;和2016版本差異不大。 轉載于:https://www.cnblogs.com/kelamoyujuzhen/p/10253278.html

Google, 請不要離開我們!

雖然我是.net陣營, 力挺Silverlight, 但是我真心希望谷歌留在中國, 如果她能夠靠談判求的言論自由的權利, 那將對中國的擁有自由信仰的一族產生重大的影響. 谷歌離開了中國, 不是她想拋棄中國市場, 而是中國決策者背叛了人性. 在此留下 Google 2010年1月14日的logo, 智慧的幽默…

高級php面試題及部分答案

轉載鏈接&#xff1a;http://www.2cto.com/kf/201304/201112.html 一. 基本知識點 1.1 HTTP協議中幾個狀態碼的含義:503 500 401 403 404 200 301 302。。。 200 : 請求成功&#xff0c;請求的數據隨之返回。 301 : 永久性重定向。 302 : 暫時行重定向。 401 : 當前請求需要用…

iec104點號_IEC104報文流程(有常用類型標識解釋)

參數地址圍類別97版基地址2002版基地址遙信1H------400H1H------4000H遙測701H------900H4001H------5000H遙控B01------B806001H------6100H設點B81H------C00H6201H------6400H電度C01H------C80H6401H------6600H遙測和遙信個數不設置上限&#xff0c;可以沒有上限限制&…

本周ASP.NET英文技術文章推薦[04/08 - 04/14](附贈自彈超級瑪麗主題曲)

摘要 本期共有6篇文章&#xff1a; ASP.NET編譯問題的公開Hotfix補丁 期待下個版本AjaxPro 的發布 在ASP.NET 2.0中使用MultiView控件實現多頁面表單 數據綁定的技巧&#xff1a;嵌套Eval語句 在ASP.NET 2.0中訪問并更新數據&#xff1a;使用數據源控件以編程方式訪問數據 AD…

一個離開某門戶網站人員自爆黑幕

去年&#xff0c;我已在星星發表了一個關于免費發短信的各類軟件的黑幕所在。而事實上的SMS&#xff08;即短信&#xff09;的黑幕遠不止于此&#xff0c;今天&#xff0c;我終于有空坐下來&#xff0c;把其中的一些讓你感覺平常卻實際觸目驚心的事情告訴你們&#xff0c;讓你們…

28歲自學3年前端成功轉行的勵志故事

為什么轉行因為混得不好。在成為程序員之前&#xff0c;我干過很多工作。由于學歷的問題&#xff08;高中&#xff09;&#xff0c;我的工作基本上都是體力活。包括但不限于&#xff1a;工廠普工、銷售&#xff08;沒有干銷售的才能&#xff09;、搬運工、擺地攤等&#xff0c;…

css中!important的作用

轉載鏈接&#xff1a;http://www.cnblogs.com/guoguo-15/archive/2011/08/24/2151859.html css中!important的作用 {*rule !important}這個css規則當今在網頁制作的時候的普及已經非常流行了&#xff0c;以前我對它的理解就停留在‘瀏覽器是否識別階段’ 而沒有真正去研究過&am…

word2vec應用場景_word2vec的使用參數解釋和應用場景

" > corpus.txt因為這些數據雖然去除了其他標簽的數據&#xff0c;但是卻把保留下來了&#xff0c;所以后來作者在分詞程序中去除了這個標簽我在這個[網頁](http://www.jb51.net/article/65497.htm)上找到了一個python去標簽的簡單代碼。但是沒有實驗過&#xff0c;不知…

usb 驅動

usb 驅動學習總結&#xff1a; usb 采用分層的拓撲結構&#xff0c;金字塔型&#xff0c;最多是7層。usb 是主從結構&#xff0c;主和主或者從和從之間不能交換數據。理論上一個usb主控制器最多可接127個設備&#xff0c;協議規定每個usb設備具有一個7bit的地址&#xff0c;范圍…