Python提供了接口API,通過使用API函數(shù)可以編寫Python擴(kuò)展,在Windows下可以使用VC來編譯Python擴(kuò)展。C/C++擴(kuò)展流程如下:
(1)設(shè)置編譯環(huán)境:
VC6.0下,打開tools->options->directories->show directories for,將Python安裝目錄下的inlude目錄添加到inlude files項(xiàng)中,將libs目錄添加到library files項(xiàng)中。
VC2005下,打開tools->options->項(xiàng)目和解決方案->VC++目錄,然后做相同工作。
(2)創(chuàng)建空的Win32 Dynamic-Link Library工程,添加新的source file,編寫代碼。
(3)打開settings for改為Win32 Release,單擊Link標(biāo)簽,將Release/**.dll改為Release/**.pyd;單擊C/C++標(biāo)簽,選擇Category->Code Generation,選擇Use run-time library中的Multithreaded DLL項(xiàng)。
(4)單擊Build->Batch Build,去掉**-Win32 Debug單選框,然后點(diǎn)擊Build。
(5)調(diào)用該模塊:import **。
注意:Python的安裝程序中不包含debug版的庫文件,不能生成debug版的Python擴(kuò)展。

下面具體講述第(2)步中如何編寫擴(kuò)展代碼:
(1)頭文件
因?yàn)镻ython含有一些預(yù)處理定義,所以必須在所有非標(biāo)準(zhǔn)頭文件導(dǎo)入之前導(dǎo)入Python.h 。Python.h中所有用戶可見的符號都有 Py 或 PY 的前綴,除非定義在標(biāo)準(zhǔn)頭文件中。為了方便,“Python.h” 也包含了一些常用的標(biāo)準(zhǔn)頭文件,包括<stdio.h>,<string.h>,<errno.h>,<stdlib.h>。如果你的系統(tǒng)沒有后面的頭文件,則會直接定義函數(shù) malloc() 、 free() 和 realloc() 。

(2)初始化函數(shù)
PyMODINIT_FUNC init**()
{
 PyObject *mod;
mod = Py_InitModule(“**”, **Methods);
}
該初始化函數(shù)必須存在,用于python解釋器對模塊進(jìn)行正確的初始化,并作為DLL文件的導(dǎo)出函數(shù)。Py_InitModule函數(shù)原型為:PyObject* Py_InitModule(char *name, PyMethodDef *methods),methods為方法列表,該函數(shù)返回一個指針指向剛創(chuàng)建的模塊對象。他是有可能發(fā)生嚴(yán)重錯誤的,也有可能在無法正確初始化時返回NULL。

(3)方法列表
static PyMethodDef **Methods[] =
{
 {“FuncName”, Func, METH_VARARGS, “…………..”},
 {NULL, NULL, 0, NULL}
};
方法列表中包含Python擴(kuò)展中的所有可以調(diào)用的函數(shù)方法,應(yīng)該被聲明為“static PyMethodDef”。每個函數(shù)對應(yīng)的括號里包括函數(shù)名、函數(shù)、調(diào)用方法和描述。其中調(diào)用方法應(yīng)該為METH_VARARGS或者M(jìn)ETH_VARARGS|METH_KEYWORDS或者0(代表使用PyArg_ParseTuple()的陳舊變量)。方法列表應(yīng)該由{NULL, NULL, 0, NULL}作為結(jié)束。

(3)函數(shù)實(shí)現(xiàn)
PyObject* Func(PyObject * self, PyObject *args)
{
 …………………..
}
所有函數(shù)都應(yīng)該被聲明為PyObject*的類型,每個函數(shù)含有兩個PyObject*型的參數(shù),參數(shù)self只有在函數(shù)為Python的內(nèi)置方法時才被使用,否則為空指針;args為向方法傳遞的參數(shù),根據(jù)方法列表中調(diào)用方法的不同而依次使用PyArg_ParseTuple和PyArg_ParseTupleAndKeywords函數(shù)處理參數(shù)。PyArg_ParseTuple函數(shù)原型如下:
int PyArg_ParseTuple(PyObject *args, const char *format, …………..);
函數(shù)PyArg_ParseTuple()檢查參數(shù)類型并轉(zhuǎn)換成C值。它使用模板字符串檢測需要的參數(shù)類型,正常返回非零,并已經(jīng)按照提供的地址存入了各個變量值,如果出錯(零)則應(yīng)該讓函數(shù)返回NULL以通知解釋器出錯。該函數(shù)使用&向后面的可變參數(shù)傳遞值;format參數(shù)指定了后面的參數(shù)類型,如”iss”表示后面的參數(shù)類型分別為int、char*、char*。常見參數(shù)類型字符如下:
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
函數(shù)必須返回一個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環(huán)境下該代碼出現(xiàn)問題,后查找原因發(fā)現(xiàn)初始化函數(shù)已經(jīng)變?yōu)?/span>PyInit_**(工程名字、初始化名字和生成的pyd名字必須一樣),而Py_InitModule也變?yōu)?/span>PyModule_Create了。具體待查。