您的位置:首页 > 编程语言 > Python开发

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所示。



图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
双精度型
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: