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.mzph.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;范围…