Python提供了接口API,通过使用API函数可以编写Python扩展,在Windows下可以使用VC来编译Python扩展。C/C++扩展流程如下:
(1)设置编译环境:
VC6.0下,打开tools->options->directories->show directories for,将Python安装目录下的inlude目录添加到inlude files项中,将libs目录添加到library files项中。
VC2005下,打开tools->options->项目和解决方案->VC++目录,然后做相同工作。
(2)创建空的Win32 Dynamic-Link Library工程,添加新的source file,编写代码。
(3)打开settings for改为Win32 Release,单击Link标签,将Release/**.dll改为Release/**.pyd;单击C/C++标签,选择Category->Code Generation,选择Use run-time library中的Multithreaded DLL项。
(4)单击Build->Batch Build,去掉**-Win32 Debug单选框,然后点击Build。
(5)调用该模块:import **。
注意:Python的安装程序中不包含debug版的库文件,不能生成debug版的Python扩展。

下面具体讲述第(2)步中如何编写扩展代码:
(1)头文件
因为Python含有一些预处理定义,所以必须在所有非标准头文件导入之前导入Python.h 。Python.h中所有用户可见的符号都有 Py 或 PY 的前缀,除非定义在标准头文件中。为了方便,“Python.h” 也包含了一些常用的标准头文件,包括<stdio.h>,<string.h>,<errno.h>,<stdlib.h>。如果你的系统没有后面的头文件,则会直接定义函数 malloc() 、 free() 和 realloc() 。

(2)初始化函数
PyMODINIT_FUNC init**()
{
 PyObject *mod;
mod = Py_InitModule(“**”, **Methods);
}
该初始化函数必须存在,用于python解释器对模块进行正确的初始化,并作为DLL文件的导出函数。Py_InitModule函数原型为:PyObject* Py_InitModule(char *name, PyMethodDef *methods),methods为方法列表,该函数返回一个指针指向刚创建的模块对象。他是有可能发生严重错误的,也有可能在无法正确初始化时返回NULL。

(3)方法列表
static PyMethodDef **Methods[] =
{
 {“FuncName”, Func, METH_VARARGS, “…………..”},
 {NULL, NULL, 0, NULL}
};
方法列表中包含Python扩展中的所有可以调用的函数方法,应该被声明为“static PyMethodDef”。每个函数对应的括号里包括函数名、函数、调用方法和描述。其中调用方法应该为METH_VARARGS或者METH_VARARGS|METH_KEYWORDS或者0(代表使用PyArg_ParseTuple()的陈旧变量)。方法列表应该由{NULL, NULL, 0, NULL}作为结束。

(3)函数实现
PyObject* Func(PyObject * self, PyObject *args)
{
 …………………..
}
所有函数都应该被声明为PyObject*的类型,每个函数含有两个PyObject*型的参数,参数self只有在函数为Python的内置方法时才被使用,否则为空指针;args为向方法传递的参数,根据方法列表中调用方法的不同而依次使用PyArg_ParseTuple和PyArg_ParseTupleAndKeywords函数处理参数。PyArg_ParseTuple函数原型如下:
int PyArg_ParseTuple(PyObject *args, const char *format, …………..);
函数PyArg_ParseTuple()检查参数类型并转换成C值。它使用模板字符串检测需要的参数类型,正常返回非零,并已经按照提供的地址存入了各个变量值,如果出错(零)则应该让函数返回NULL以通知解释器出错。该函数使用&向后面的可变参数传递值;format参数指定了后面的参数类型,如”iss”表示后面的参数类型分别为int、char*、char*。常见参数类型字符如下:
s      char*
s#    char*, int
z      char*          //can be null
z#    char*, int    //char* can be null
i       int
l       long int
c     char
f      float
d    double
函数必须返回一个PY对象,这可以通过Py_BuildValue()来完成,其形式与PyArg_ParseTuple()很像,获取格式字符串和C值,并返回新的Python对象。

代码示例:

#include <python.h>
#include 
<windows.h>

static 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, 0, NULL}
}
;

PyMODINIT_FUNC initmyext(
void)
{
    PyObject 
*mod;
    mod 
= Py_InitModule("myext", myextMethods);   
}


注意:在Python3.1环境下该代码出现问题,后查找原因发现初始化函数已经变为PyInit_**(工程名字、初始化名字和生成的pyd名字必须一样),而Py_InitModule也变为PyModule_Create了。具体待查。