首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > perl python >

Python之美[从初学者到高手]-一步一步动手给Python写扩展(错误处理和引用计数)

2013-10-08 
Python之美[从菜鸟到高手]--一步一步动手给Python写扩展(异常处理和引用计数)我们将继续一步一步动手给Pyt

Python之美[从菜鸟到高手]--一步一步动手给Python写扩展(异常处理和引用计数)

    我们将继续一步一步动手给Python写扩展,通过上一篇我们学习了如何写扩展,本篇将介绍一些高级话题,如异常,引用计数问题等。强烈建议先看上一篇,Python之美[从菜鸟到高手]--一步一步动手给Python写扩展(爱之初体验)的基础知识。


一:扩展中的异常处理

    高级语言如C++,Java等都有完善的异常控制,Python也不例外。但与C++不同的是,写C++你可以完全抛弃异常处理,但Python中基本是不可能的。记得Google的C++编码规范中明确指出,他们是不允许使用异常的,因为会打乱控制流,导致调试等复杂度增加,有兴趣的童鞋可以看看。但Python中你是避免不了的,很多内置函数和模块都大量的使用了异常。所以为了我们编写的模块更加Pythonic,异常处理免不了。

下面一段代码是在上一篇文章中的增强版,主要就是在异常处理方面。


   通过dir(),我们发现新增加了error和IoError,我们看看这到底是什么?

Python之美[从初学者到高手]-一步一步动手给Python写扩展(错误处理和引用计数)

   哦,原来spam.error就是一个异常类,是通过代码39行加入:PyModule_AddObject的函数原形,int PyModule_AddObject(PyObject *module, const char *name, PyObject *value),其中module就是Py_InitModule()返回的对象。代码39行:PyModule_AddObject(m,"error",SpamError),含义就是将SpamError这个类加入m这个模块中,并简记为“error”。而SpamError就是一个异常类,是通过35行的SpamError=PyErr_NewException("spam.error",NULL,NULL)创建的,PyObject* PyErr_NewException(char *name, PyObject *base, PyObject *dict)返回一个新创建的异常类,SpamError是程序开头定义的一个静态变量,到这里我们都知道了异常类如何定义了,那如何使用呢?

   代码14行,当系统调用失败,通过PyErr_SetString(SpamError,"system call failed")设置异常,一般都是使用void PyErr_SetString(PyObject *type, const char *message)来设置异常,代码很简洁,下面通过实例看看如何使用。

Python之美[从初学者到高手]-一步一步动手给Python写扩展(错误处理和引用计数)

  我们调用了一个不存在的命令,很明显抛出的是IoError,额突然发现名字起的不好,应该为NotFound异常更加贴切。

  这里需要注意37行的Py_INCREF(SpamError),由于异常可以由外部代码删除,这样将导致SpamError成为悬垂指针(也就是SpamError指向的地址被释放,但SpamError还是指向原来的地址),所以将SpamError的引用加1,这样异常类就不会被释放。

   下面是几点扩展知识点:

1,如果要忽略函数抛出的异常,可以用PyErr_Clear()。因为异常只有传递到Python解释器时才起作用,所以在C API层次可以清除。

2,如果是申请内存函数(malloc等)失败,要设置异常,需要设置PyErr_NoMemory(),并需要将异常指示器返回,简单来说就是这样:return PyErr_NoMemory();

主要是所有的对象创建函数都是这么干的,所以我们要遵守规矩。

   下面给一个demo程序,也就是上面代码的演化版,增加了异常清除,给模块增加变量,如模块版本信息,作者等。


   从上面我们可以看出,的确没有抛出异常,而且返回值也的确是0。


二,引用计数

  Python中使用了引用计数(为主)来解决垃圾回收,想了解Python如何进行垃圾回收可以看Python之美[从菜鸟到高手]--Python垃圾回收机制及gc模块详解。那么在C API层次如何控制引用的呢?

  常用的有4个C API,

voidno_bug(PyObject *list){    PyObject *item = PyList_GetItem(list, 0);    Py_INCREF(item);    PyList_SetItem(list, 1, PyInt_FromLong(0L));    PyObject_Print(item, stdout, 0);    Py_DECREF(item);}


热点排行