Python的扩展
2012-07-10 11:35
176 查看
本文摘自《征服Python—语言基础与典型应用》,第八章——Python的扩展与嵌入
由于Python是解释性的脚本语言,执行速度较慢。在某些需要提高脚本执行效率的情况下,可以考虑扩展Python,用C/C++来完成对效率要求高的部分。另外,由于Python功能强大,完全可以将其嵌入到C/C++中,以简化程序,减少代码。
8.1
扩展Python
Python提供了支持C/C++接口,可以方便地使用C/C++来扩展Python。用C/C++编写的Python扩展主要用于完成底层的系统操作,以及提高执行速度等。
8.1.1
扩展概述
Python提供了接口API,通过使用API函数可以编写Python扩展。在Windows下可以使用VC来编译Python扩展。在UNIX和Linux下则可以使用gcc来编译。
1.设置编程环境
使用VC时需要设置一些头文件以及库文件的包含目录。如果使用VC++ 6.0,则设置过程如下所示。
(1)单击【Tools】|【Options】命令,弹出如图8-1所示的对话框。
(2)单击【Directories】标签,选择【Show directories for】下拉列表框中的【Include files】项,将Python安装目录下的INCLUDE目录添加到【Directories】列表中,如图8-2所示。
(3)选择【Show directories for】下拉列表框中的【Library files】项,将Python安装目录下的LIBS目录添加到【Directories】列表中,如图8-3所示。
(4)单击【OK】按钮完成操作。
如果使用Visual Studio 2005,则设置过程如下所示。
(1)单击【工具】|【选项】命令,弹出如图8-4所示的对话框。
(2)双击左侧列表树中的【项目和解决方案】项,选择【VC++目录】项,如图8-5所示。
(3)选择【显示以下内容的目录】下拉列表框中的【包含文件】项,将Python安装目录下的include目录添加到列表中,如图8-6所示。
(4)选择【显示以下内容的目录】下拉列表框中的【库文件】项,将Python安装目录下的libs目录添加到列表中,如图8-7所示。
(5)单击【确定】按钮完成操作。
2.创建工程
在Visual C++ 6.0中创建Python扩展过程如下所示。
(1)单击【File】|【New】命令,弹出创建工程对话框。单击【Projects】标签,选择左侧列表中的【Win32 Dynamic-Link Library】项,在【Project name】文本框中输入工程名“myext”,如图8-8所示。
(2)单击【OK】按钮,弹出如图8-9所示的工程设置对话框。选中【An empty DLL project.】单选框。
(3)单击【Finish】按钮弹出如图8-10所示的确认对话框。单击【OK】按钮完成工程创建。
(4)单击【File】|【New】命令弹出创建文件对话框,单击【Files】标签。选择左侧列表中的【C++ Source File】项,在【File】文本框中输入文件名“myext.c”,如图8-11所示。
(5)单击【OK】按钮,在“myext.c”中添加如下内容。
(7)选择【Settings For】下拉列表框中的【Win32 Release】项。单击【Link】标签,将【Outpub file name】文本框中的“Release/myext.dll” 改为“Release/myext.pyd”,如图8-13所示。
(8)单击【C/C++】标签,选择【Category】下拉列表框中的【Code Generation】项,选择【Use run-time library】下拉列表框中的【Multithreaded DLL】项,如图8-14所示。
(9)单击【OK】按钮完成工程设置。
(10)单击【Build】|【Batch Build】命令,弹出如图8-15所示的对话框,将【myext-Win32 Debug】单选框前的勾去掉。单击【Build】按钮生成Python扩展。
编译完成后将在工程目录下的Release目录中生成“myext.pyd”文件,其为所编写的Python扩展。编写“usemyext.py”调用“myext.pyd”中的函数。代码如下所示。
由于Python官方的安装程序中不包含debug版的库文件,不能生成debug版的Python扩展,因此上述设置都是针对release版。如果需要生成debug版的Python扩展,则需要自己编译Python生成debug版的库文件。另外,使用Visual
Studio 2005编译Python扩展与上述过程类似,这里不再赘述。
图8-16 使用Python扩展
8.1.2 程序详解
一般的Python扩展程序中应包含以下3部分内容。
1.初始化函数
初始化函数是必须的,用于Python解释器对模块进行正确的初始化。初始化函数的函数名必须以init开头,并加上模块的名字。例如上节中初始化函数的函数名为“initmyext”,其中“myext”为模块名。函数“initmyext”代码如下所示。
PyObject* Py_InitModule( char *name, PyMethodDef *methods) 其参数含义如下。
• name:模块名。
• methods:方法列表。
2.方法列表
方法列表中包含了Python扩展中的所有可以调用的函数方法。方法列表应该被声明为“static PyMethodDef”。上一节实例中的方法列表如下所示。
3.函数实现每一个函数方法对应于方法列表中的由大括号包围的一项。大括号中由4部分组成,模块中的方法名,与之对应的Python扩展中的函数名、函数调用方法,以及方法描述。其中函数调用方法应该为“METH_VARARGS”或者“METH_VARARGS | METH_KEYWORDS”。也可以将函数调用方法设置为0。方法列表应该以由两个NULL组成的一项来表示结束。
方法列表中包含了模块中方法对应的C语言函数实现。在Python扩展中所有的函数都应该被声明为“PyObject *”型,每个函数都应当含有两个“PyObject *”型的参数。在上一节的实例中,模块方法的实现函数如下所示。
int PyArg_ParseTuple( PyObject *args, const char *format, ...)
其参数含义如下。
• format:参数类型描述。
PyArg_ParseTuple为可变参数函数,其后的参数即在函数中接受Python中传递参数的变量。在上述的show函数中,要使用3个参数,分别为hwnd、message、title。在PyArg_ParseTuple中将其作为参数,使用“&”向hwnd、message、title传递值,即将Python向show方法传递的参数依次赋值给hwnd、message、title。
PyArg_ParseTuple函数中的format参数指定了其后参数的类型,在show函数中format参数为“iss”表示hwnd为整型,message和title为字符串。常见的指定参数类型的字符如表8-1所示。
表8-1 常见的指定参数类型的字符
续表
由于Python是解释性的脚本语言,执行速度较慢。在某些需要提高脚本执行效率的情况下,可以考虑扩展Python,用C/C++来完成对效率要求高的部分。另外,由于Python功能强大,完全可以将其嵌入到C/C++中,以简化程序,减少代码。
8.1
扩展Python
Python提供了支持C/C++接口,可以方便地使用C/C++来扩展Python。用C/C++编写的Python扩展主要用于完成底层的系统操作,以及提高执行速度等。
8.1.1
扩展概述
Python提供了接口API,通过使用API函数可以编写Python扩展。在Windows下可以使用VC来编译Python扩展。在UNIX和Linux下则可以使用gcc来编译。
1.设置编程环境
使用VC时需要设置一些头文件以及库文件的包含目录。如果使用VC++ 6.0,则设置过程如下所示。
(1)单击【Tools】|【Options】命令,弹出如图8-1所示的对话框。
(2)单击【Directories】标签,选择【Show directories for】下拉列表框中的【Include files】项,将Python安装目录下的INCLUDE目录添加到【Directories】列表中,如图8-2所示。
(3)选择【Show directories for】下拉列表框中的【Library files】项,将Python安装目录下的LIBS目录添加到【Directories】列表中,如图8-3所示。
(4)单击【OK】按钮完成操作。
如果使用Visual Studio 2005,则设置过程如下所示。
(1)单击【工具】|【选项】命令,弹出如图8-4所示的对话框。
(2)双击左侧列表树中的【项目和解决方案】项,选择【VC++目录】项,如图8-5所示。
(3)选择【显示以下内容的目录】下拉列表框中的【包含文件】项,将Python安装目录下的include目录添加到列表中,如图8-6所示。
图8-1 Options对话框 |
图8-2 添加头文件 |
图8-3 添加库文件 |
图8-4 选项对话框 |
图8-5 设置VC++目录 |
图8-6 添加头文件 |
(4)选择【显示以下内容的目录】下拉列表框中的【库文件】项,将Python安装目录下的libs目录添加到列表中,如图8-7所示。
(5)单击【确定】按钮完成操作。
图8-7 添加库文件 |
2.创建工程
在Visual C++ 6.0中创建Python扩展过程如下所示。
(1)单击【File】|【New】命令,弹出创建工程对话框。单击【Projects】标签,选择左侧列表中的【Win32 Dynamic-Link Library】项,在【Project name】文本框中输入工程名“myext”,如图8-8所示。
(2)单击【OK】按钮,弹出如图8-9所示的工程设置对话框。选中【An empty DLL project.】单选框。
图8-8 创建工程对话框 |
图8-9 工程设置对话框 |
(3)单击【Finish】按钮弹出如图8-10所示的确认对话框。单击【OK】按钮完成工程创建。
(4)单击【File】|【New】命令弹出创建文件对话框,单击【Files】标签。选择左侧列表中的【C++ Source File】项,在【File】文本框中输入文件名“myext.c”,如图8-11所示。
图8-10 确认对话框 |
图8-11 添加文件 |
(5)单击【OK】按钮,在“myext.c”中添加如下内容。
#include "Python.h" #include "windows.h" PyObject *show(PyObject *self, PyObject *args) { char *message; const char *title = NULL; HWND hwnd = NULL; int r; if (!PyArg_ParseTuple(args, "iss", &hwnd, &message, &title)) return NULL; r = MessageBox(hwnd,message, title, MB_OK); return Py_BuildValue("i", r); } static PyMethodDef myextMethods[] = { {"show", show, METH_VARARGS,"show a messagebox"}, {NULL,NULL} }; PyMODINIT_FUNC initmyext() { PyObject *mod; mod = Py_InitModule("myext",myextMethods); }(6)单击【Project】|【Settings】命令,弹出如图8-12所示的工程设置对话框。
(7)选择【Settings For】下拉列表框中的【Win32 Release】项。单击【Link】标签,将【Outpub file name】文本框中的“Release/myext.dll” 改为“Release/myext.pyd”,如图8-13所示。
图8-12 工程设置对话框 |
图8-13 设置Link选项 |
(8)单击【C/C++】标签,选择【Category】下拉列表框中的【Code Generation】项,选择【Use run-time library】下拉列表框中的【Multithreaded DLL】项,如图8-14所示。
(9)单击【OK】按钮完成工程设置。
(10)单击【Build】|【Batch Build】命令,弹出如图8-15所示的对话框,将【myext-Win32 Debug】单选框前的勾去掉。单击【Build】按钮生成Python扩展。
图8-14 设置C/C++选项 |
图8-15 编译工程 |
编译完成后将在工程目录下的Release目录中生成“myext.pyd”文件,其为所编写的Python扩展。编写“usemyext.py”调用“myext.pyd”中的函数。代码如下所示。
# -*- coding:utf-8 -*- # file: usemyext.py import myext # 导入myext模块 print myext.show(0, 'Extend Python', 'Python') # 调用show函数脚本运行后如图8-16所示。
由于Python官方的安装程序中不包含debug版的库文件,不能生成debug版的Python扩展,因此上述设置都是针对release版。如果需要生成debug版的Python扩展,则需要自己编译Python生成debug版的库文件。另外,使用Visual
Studio 2005编译Python扩展与上述过程类似,这里不再赘述。
图8-16 使用Python扩展
8.1.2 程序详解
一般的Python扩展程序中应包含以下3部分内容。
1.初始化函数
初始化函数是必须的,用于Python解释器对模块进行正确的初始化。初始化函数的函数名必须以init开头,并加上模块的名字。例如上节中初始化函数的函数名为“initmyext”,其中“myext”为模块名。函数“initmyext”代码如下所示。
PyMODINIT_FUNC initmyext() { PyObject *mod; mod = Py_InitModule("myext",myextMethods); }PyObject* Py_InitModule( char *name, PyMethodDef *methods)其中PyMODINIT_FUNC为Python头文件中定义的宏,在Windows下其相当于_declspec(dllexport) void,即将initmyext声明为void型,并且将其设为DLL文件的导出函数。初始化函数中的Py_InitModule函数,其函数原型如下所示。
PyObject* Py_InitModule( char *name, PyMethodDef *methods) 其参数含义如下。
• name:模块名。
• methods:方法列表。
2.方法列表
方法列表中包含了Python扩展中的所有可以调用的函数方法。方法列表应该被声明为“static PyMethodDef”。上一节实例中的方法列表如下所示。
static PyMethodDef myextMethods[] = { {"show", show, METH_VARARGS,"show a messagebox"}, {NULL,NULL} };
3.函数实现每一个函数方法对应于方法列表中的由大括号包围的一项。大括号中由4部分组成,模块中的方法名,与之对应的Python扩展中的函数名、函数调用方法,以及方法描述。其中函数调用方法应该为“METH_VARARGS”或者“METH_VARARGS | METH_KEYWORDS”。也可以将函数调用方法设置为0。方法列表应该以由两个NULL组成的一项来表示结束。
方法列表中包含了模块中方法对应的C语言函数实现。在Python扩展中所有的函数都应该被声明为“PyObject *”型,每个函数都应当含有两个“PyObject *”型的参数。在上一节的实例中,模块方法的实现函数如下所示。
PyObject *show(PyObject *self, PyObject *args) { char *message; const char *title = NULL; HWND hwnd = NULL; int r; if (!PyArg_ParseTuple(args, "iss", &hwnd, &message, &title)) return NULL; r = MessageBox(hwnd,message, title, MB_OK); return Py_BuildValue("i", r); }• args:传递的参数。其中参数self只有在函数为Python的内置方法时才被使用,其余情况下self为一个空指针。参数args为在Python中向方法传递的参数。如果在方法列表中指定的函数调用方法为“METH_VARARGS”,则在函数中使用PyArg_ParseTuple处理参数。如果在方法列表中指定的函数调用方法为“METH_VARARGS | METH_KEYWORDS”,则应该使用PyArg_ParseTupleAndKeywords处理参数。其中PyArg_ParseTuple的函数原型如下所示。
int PyArg_ParseTuple( PyObject *args, const char *format, ...)
其参数含义如下。
• format:参数类型描述。
PyArg_ParseTuple为可变参数函数,其后的参数即在函数中接受Python中传递参数的变量。在上述的show函数中,要使用3个参数,分别为hwnd、message、title。在PyArg_ParseTuple中将其作为参数,使用“&”向hwnd、message、title传递值,即将Python向show方法传递的参数依次赋值给hwnd、message、title。
PyArg_ParseTuple函数中的format参数指定了其后参数的类型,在show函数中format参数为“iss”表示hwnd为整型,message和title为字符串。常见的指定参数类型的字符如表8-1所示。
表8-1 常见的指定参数类型的字符
格式化字符 | C数据类型 | Python类型 |
s | char* | 字符串 |
s# | char*, int | 字符串及长度 |
z | char* | 与s相同,但可以为NULL |
格式化字符 | C数据类型 | Python类型 |
z# | char*, int | 与s#相同,但可以为NULL |
i | int | 长整型 |
l | long int | 长整型 |
c | char | 单个字符的字符串 |
f | float | 双精度型 |
d | double | 双精度型 |
相关文章推荐
- python进程间传递文件描述符扩展库
- ida python扩展安装
- 再探C/C++扩展Python
- 使用C/C++扩展Python
- 29. Python脚本学习笔记二十九 扩展Python以及SWIG
- 使用C或C++扩展python
- Python的路径及C语言扩展
- pjsip的python扩展使用
- 将pjsip的python扩展从python2.4升级到python3.2
- 用C语言扩展Python的功能
- 用Cython编译Python的C扩展
- python PIL/Pillow图像扩展、复制、粘贴处理
- python - Flask - 扩展
- snmp开发记录2--使用python扩展
- Python 的C语言扩展
- Python学习之使用ctypes模块操作C扩展程序
- Python之Web前端jQuery扩展
- python扩展tre
- 用CONNECT方法突破HTTP代理服务器的扩展名封锁(python) (转)
- python3学习之类成员、扩展父类方法的功能