Extending Python with C\C++ 实践问题
2015-04-21 13:46
211 查看
python doc:Extending Python
根据上面的内容,可编写如下程序:
利用codeblocks新建工程,编译dll, 具体操作步骤可参考Python之美[从菜鸟到高手]。通过这篇文章,我成功在python里调用到了spam.system(‘ls -s’)。
编译出错,出现错误:undefined reference to _imp__PyErr_SetString, 缺少库文件,需要把libpython26.a添加到codeblocks的链接库中,和python26.lib一块。然后就可以编译成功了。其中的PyExc_ArithmeticError是预定义的一些标准异常,可参考标准异常。编译成功后,在python中调用如下:
编译后,在python中调用,结果:
异常的名字为error111,异常信息something is wrong。当在python IDLE中导入spam,可发现:
spam.error111是异常对象SpamError所属异常类的名字,PyModule_AddObject则把对象SpamError添加到模块m(spam模块)的属性字典中,key是error222。
用上面代码替换第2节对应位置,编译后,在python执行:
返回ArithmeticError而不是SpamError。
编译后,python调用:
上面这个异常,可能是return NULL造成的,前面的异常被忽略了。
“s”表示传入一个字符串参数,即python调用为:
而如果修改格式字符串:
就表示传入一个元组参数,即python调用为:
然后可以解析元组的多个参数,修改C代码如下:
编译后,python调用如下:
返回值为一个元组,对应每一个命令的返回值。s或者i分别表示字符串和整数,具体可参考Python官方文档参数解析及值的构造,其中包含了各种类型的格式化字符。
继续实践,字符串和整数的:
python调用为:
注意:PyArg_ParseTuple()的后面的参数,都是一些地址!
根据上面的内容,可编写如下程序:
#include <Python.h> static PyObject *spam_system(PyObject *self, PyObject *args) { const char *command; int sts; if (!PyArg_ParseTuple(args, "s", &command)) return NULL; sts = system(command); return Py_BuildValue("i", sts); } static PyMethodDef SpamMethods[] = { {"system", spam_system, METH_VARARGS,"Execute a shell command."}, {NULL, NULL, 0, NULL} }; PyMODINIT_FUNC initspam(void) { Py_InitModule("spam", SpamMethods); }
利用codeblocks新建工程,编译dll, 具体操作步骤可参考Python之美[从菜鸟到高手]。通过这篇文章,我成功在python里调用到了spam.system(‘ls -s’)。
1 标准异常
阅读python官方文档Extending Python with C\C++后,第二小节是关于异常的,我试着在上面代码中加入异常的语句,如下:#include <Python.h> static PyObject *spam_system(PyObject *self, PyObject *args) { const char *command; int sts; if (!PyArg_ParseTuple(args, "s", &command)) return NULL; sts = system(command); if (sts > 0) //添加异常,如果系统没有传入的命令,返回值不为0 { //这里的异常PyExc_ArithmeticError是我随便选的预定义异常对象 PyErr_SetString(PyExc_ArithmeticError, "something is wrong"); return NULL; } return Py_BuildValue("i", sts); } static PyMethodDef SpamMethods[] = { {"system", spam_system, METH_VARARGS,"Execute a shell command."}, {NULL, NULL, 0, NULL} }; PyMODINIT_FUNC initspam(void) { Py_InitModule("spam", SpamMethods); }
编译出错,出现错误:undefined reference to _imp__PyErr_SetString, 缺少库文件,需要把libpython26.a添加到codeblocks的链接库中,和python26.lib一块。然后就可以编译成功了。其中的PyExc_ArithmeticError是预定义的一些标准异常,可参考标准异常。编译成功后,在python中调用如下:
>>>import spam >>> spam.system('lll') Traceback (most recent call last): File "<pyshell#12>", line 1, in <module> spam.system('lll') ArithmeticError: something is wrong >>> spam.system('ls -s') 0 >>>
2 自定义异常
下面就是自定义异常:#include <Python.h> static PyObject *SpamError; static PyObject *spam_system(PyObject *self, PyObject *args) { const char *command; int sts; if (!PyArg_ParseTuple(args, "s", &command)) return NULL; sts = system(command); if (sts > 0) { PyErr_SetString(SpamError, "something is wrong"); return NULL; } return Py_BuildValue("i", sts); } static PyMethodDef SpamMethods[] = { {"system", spam_system, METH_VARARGS,"Execute a shell command."}, {NULL, NULL, 0, NULL} }; PyMODINIT_FUNC initspam(void) { PyObject *m; m = Py_InitModule("spam", SpamMethods); if (m == NULL) return; SpamError = PyErr_NewException("spam.error111", NULL, NULL); Py_INCREF(SpamError); PyModule_AddObject(m, "error222", SpamError); }
编译后,在python中调用,结果:
>>> import spam >>> spam.system('lll') Traceback (most recent call last): File "<pyshell#15>", line 1, in <module> spam.system('lll') error111: something is wrong >>>
异常的名字为error111,异常信息something is wrong。当在python IDLE中导入spam,可发现:
>>> spam.error222 <class 'spam.error111'> >>>
spam.error111是异常对象SpamError所属异常类的名字,PyModule_AddObject则把对象SpamError添加到模块m(spam模块)的属性字典中,key是error222。
3 其它
1. PyErr_Occurred()
PyErr_Occurred 用来判断是否产生了一个异常,如果没有,返回NULL,PyErr_Occurred() == NULL 返回True;如果有异常,该函数返回最近的一个异常对象,可使用PyErr_ExceptionMatches()进行对比:if (sts > 0) { PyErr_SetString(SpamError, "something is wrong"); if(PyErr_ExceptionMatches(SpamError)) { PyErr_SetString(PyExc_ArithmeticError, "PyExc_ArithmeticError"); return NULL; } return NULL; } return Py_BuildValue("i", sts);
用上面代码替换第2节对应位置,编译后,在python执行:
>>> import spam >>> spam.system('lll') Traceback (most recent call last): File "<pyshell#19>", line 1, in <module> spam.system('lll') ArithmeticError: PyExc_ArithmeticError >>>
返回ArithmeticError而不是SpamError。
2. PyErr_Clear()
如果要忽略不处理异常,可调用PyErr_Clear():if (sts > 0) { PyErr_SetString(SpamError, "something is wrong"); PyErr_Clear(); return NULL; } return Py_BuildValue("i", sts);
编译后,python调用:
>>> import spam >>> spam.system('lll') Traceback (most recent call last): File "<pyshell#21>", line 1, in <module> spam.system('lll') SystemError: error return without exception set >>>
上面这个异常,可能是return NULL造成的,前面的异常被忽略了。
3. PyArg_ParseTuple()
这个函数是用来解析元组参数的。前面的代码部分:if (!PyArg_ParseTuple(args, "s", &command)) return NULL;
“s”表示传入一个字符串参数,即python调用为:
>>>spam.system('ls -s')
而如果修改格式字符串:
if (!PyArg_ParseTuple(args, "(s)", &command)) return NULL;
就表示传入一个元组参数,即python调用为:
>>> spam.system(('ls -s',)) 0 >>>
然后可以解析元组的多个参数,修改C代码如下:
static PyObject *spam_system(PyObject *self, PyObject *args) { const char *command1; const char *command2; int sts1, sts2; if (!PyArg_ParseTuple(args, "(ss)", &command1, &command2)) return NULL; sts1 = system(command1); sts2 = system(command2); if (sts1 > 0) { PyErr_SetString(SpamError, "something is wrong"); PyErr_Clear(); return NULL; } return Py_BuildValue("(ii)", sts1, sts2); }
编译后,python调用如下:
>>> spam.system(('ls -s', 'ls -s')) (0, 0) >>>
返回值为一个元组,对应每一个命令的返回值。s或者i分别表示字符串和整数,具体可参考Python官方文档参数解析及值的构造,其中包含了各种类型的格式化字符。
继续实践,字符串和整数的:
const char *command1; const char *command2; int sts1, sts2, temp; temp = 0; if (!PyArg_ParseTuple(args, "(ssi)", &command1, &command2, &temp)) return NULL; sts1 = system(command1); sts2 = system(command2); printf("%d\n", temp); return Py_BuildValue("(iii)", sts1, sts2, temp);
python调用为:
>>> import spam >>> spam.system(('ls -s', 'ls -s', 4)) (0, 0, 4) >>>
注意:PyArg_ParseTuple()的后面的参数,都是一些地址!
4. 类、对象、方法、属性
未完,待续相关文章推荐
- 用C/C++扩展Python(Extending Python with C or C++)
- 用C/C++扩展Python(Extending Python with C or C++)
- Extending Python with C or C++
- python extending with c++
- Extending Python with C or C++¶
- Extending Python with C or C++
- C++ 调用Python3 脚本中无法引入内建模块的问题 解决方法
- faster-rcnn caffe 实践和问题总结(Python)
- python与机器学实践-何宇健 源代码及过程中遇到的问题
- Python安装scrapy提示 error: Microsoft Visual C++ 14.0 is required. Get it with "Microsoft Visual C++
- 解决"python setup.py egg_info" failed with error code 1以及error: Microsoft Visual C++ 14.0 is required
- 问题:python安装mysql-python 出现Microsoft Visual C++ 9.0 is required. Get it from http://aka.ms/vcpython27
- python数据挖掘入门与实践---作者归属问题
- Python代码编码问题:SyntaxError: Non-UTF-8 code starting with '\xe4'
- c++调用python脚本出现的一些问题
- 解决python with 在写入文件是因编码格式不同而造成乱码问题
- 8皇后问题(c++/python实现)
- 解决 Command "python setup.py egg_info" failed with error code 1 问题
- C++代码中嵌入Python之后程序的发布问题
- google protocol buffer的字符编码问题(c++/java/python)