日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

Python的C/C++扩展

發布時間:2025/3/15 c/c++ 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Python的C/C++扩展 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Python的C/C++擴展

By phidoit@gmail.com



? ? 可擴展性是Python的一大特色,一方面,由于Python是解釋執行的,這導致運行速度會比編譯型語言慢,因此可以通過使用C/C++重寫核心部分代碼以解決性能上的瓶頸(程序90%的時間再運行10%的代碼);另一方面,可以通過擴展,達到添加整合一些額外的功能以及保持專有源代碼的目的。在本文接下來的部分中我們將討論如何編寫C/C++擴展代碼,并使用它們的功能。
? ? 我們要建立的是一個可以在Python內運行的C/C++模塊,因此需要解決如何使C代碼和Python代碼能夠進行交互以及數據共享。擴展是通過為C代碼編寫包裝函數(類似適配器)實現雙向交互和數據共享的。

一.一般的包裝模式

每一個包裝函數主要做三件事:
1.把輸入的Python對象轉換為C/C++對象;
2.調用C/C++函數;
3.轉換C/C++函數處理的輸出結果為Python對象,并返回;

先用一個簡單樣例描述模塊大體的過程:

//wrap.cpp

//1.C代碼

#include "Python.h"
int add(int arg1, int arg2)
{
? ? return arg1 + arg2;
}
//2.add的包裝函數:

static PyObject* wrap_add(PyObject *self, PyObject *args)
{
? ? //把輸入的Python對象轉換為C/C++能識別的數據

? ? int arg1, arg2;
? ? if(!PyArg_ParseTuple(args, "ii", &arg1, &arg2))
? ? return NULL;
? ? //調用C/C++函數,得到結果

? ? int result = add(arg1,arg2);
? ? //把得到的結果包裝成Python對象,并返回

? ? return (PyObject*)Py_BuildValue("i", result);
}
//3.為模塊添加PyMethodDef方法數組

static PyMethodDef wrap_methods[] ={
? ? {"add", wrap_add, METH_VARARGS},
? ? {NULL, NULL}
};
//4.增加模塊初始化函數InitModule

PyMODINIT_FUNC initwrap (void)
{
? ? Py_InitModule("wrap ", wrap_methods);
}

? ?
? ?把上面的代碼編譯,生成wrap.pyd。
? ?Visual Studio 2005編譯方法參考:
? ? http://blog.csdn.net/solo_lxy/archive/2007/07/20/1700515.aspx
? ?啟動控制臺切換到相應的工程目錄,即可測試生成的模塊:
? ?
? ?(PS:似乎只有Release模式生成的模塊才能正常運行)

相關說明
? ? 每個包裝函數都有如下形式:
? ?? ?? ? PyObject * wrap_function(PyObject *, PyObject * args)
? ? 函數第一個參數,有特殊用途,通常選擇忽略。第二個參數是一個PyTuple(PyObject的子類型,和Python中的Tuple對應),是調用時Python傳入的參數。
? ? 函數PyArg_ParseTuple把Python對象轉換為C的數據類型,其聲明如下:
? ?? ??? int PyArg_ParseTuple(PyObject* args, char* format, ...);
? ? 參數args必須是一個tuple對象,包含傳遞過來的參數, format 參數必須是格式化字符串。剩余參數是各個變量的地址,類型要與格式化字符串對應。如:
? ?? ??? int arg1, arg2;
? ?? ???PyArg_ParseTuple(args, "ii", &arg1, &arg2);
? ? 函數Py_BuildValue可以說是PyArg_ParseTuple的逆過程,它把C的數據類型包裝為Python對象。
? ?? ??? return (PyObject*)Py_BuildValue("i", result);
? ? 把調用C函數的結果result包裝為Python的int對象,并返回。
? ?? ???static PyMethodDef wrap_methods[] ={
? ?? ?? ?? ?{"add", wrap_add, METH_VARARGS},
? ?? ?? ?? ?{NULL, NULL}
? ?? ???};
? ? 這個數組包含多個數組,其中的每個數組都包含了一個函數的信息,以便解釋器能夠導入并調用它們,最后一個NULL數組表示列表的結束。 METH_VARARGS常量表示參數以元組形式傳入。
? ?? ???PyMODINIT_FUNC initwrap (void)
? ?? ???{
? ?? ?? ?? ?Py_InitModule("wrap ", wrap_methods);
? ?? ???}
? ? 模塊初始化函數void initModuleName(),這部分代碼在模塊被導入的時候被解釋器調用。這樣所有的包裝就已經完成了。

二.C++類的包裝


// Example.cpp

class Numbers
{
public:
? ? Numbers(int first, double second)
? ?? ???: m_first( first), m_second(second){}
? ? double NumMemberMult(void){ return m_first*m_second;}
private:
? ? int m_first;
? ? double m_second;
};
static void PyDelNumbers(void *ptr)
{
? ? Numbers * oldnum = static_cast<Numbers *>(ptr);
? ? delete oldnum;
? ? return;
}
PyObject *Example_new_Numbers(PyObject *, PyObject* args)
{
? ? int arg1;
? ? double arg2;
? ? int ok = PyArg_ParseTuple(args,"id",&arg1,&arg2);
? ? if(!ok) return NULL;
? ?//動態創建一個新對象

? ? Numbers *newnum = new Numbers(arg1, arg2);
? ?//把指針newnum包裝成PyCObject對象并返回給解釋器

? ? return PyCObject_FromVoidPtr( newnum, PyDelNumbers);
}
PyObject * Example_Numbers_MemberMult(PyObject *, PyObject* args)
{
? ? PyObject *pynum = 0;
? ? int ok = PyArg_ParseTuple( args, "O", &pynum);
? ? if(!ok) return NULL;
? ?//把PyCObject轉換為void指針

? ? void * temp = PyCObject_AsVoidPtr(pynum);
? ?//把void指針轉換為一個Numbers對象指針

? ? Numbers * thisnum = static_cast<Numbers *>(temp);
? ? //調用函數

? ? double result = thisnum->NumMemberMult();
? ? //返回結果

? ? return Py_BuildValue("d",result);
}

static PyMethodDef Example_methods[] = {
? ? {"Numbers", Example_new_Numbers, METH_VARARGS},
? ? {"NumMemberMult", Example_Numbers_MemberMult, METH_VARARGS},
? ? {NULL, NULL}
};
PyMODINIT_FUNC initExample (void)
{
? ? Py_InitModule("Example", Example_methods);
}

? ?C++類的包裝和C函數的包裝大同小異,因為對類的包裝是對函數的包裝,所以仍需要用Python代碼對擴展模塊進行包裝,才可以像類一樣的使用。

#example.py
from Example import *

class example(object):
? ? def __init__(self,arg1,arg2):
? ?? ???self._base = Numbers(arg1,arg2)
? ? def MemberMult(self):
? ?? ???return NumMemberMult(self._base)

? ?
? ?這樣C++類的包裝也完成了。

三.C/C++中創建Python list

static PyObject* Windy_dict(PyObject *self, PyObject *args)
{
? ? //創建列表
? ? PyObject *newlist = PyList_New(0);
? ? PyList_Append(newlist, PyString_FromString("first"));
? ? PyList_Append(newlist, PyString_FromString("second"));
? ? PyList_Append(newlist, PyString_FromString("third"));
? ? //返回給解釋器
? ? return newlist;
}

? ? 創建其它Python對象也類似list的創建,返回給解釋器的都是一個對象指針。C/C++對Python對象的解析差不多是創建時的逆過程。具體的對象模型及API可以查閱相關參考文檔。
Python v2.6.2 documentation ? Python/C API Reference Manual ? Concrete Objects Layer

總結

以上是生活随笔為你收集整理的Python的C/C++扩展的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。