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了。具體待查。