python擴(kuò)展1-C導(dǎo)出模塊析蝴、函數(shù)給python使用

導(dǎo)出模塊

當(dāng)python執(zhí)行import dllmodule時(shí)禁漓,執(zhí)行了以下步驟:

  1. 查找名字為dllmodule的動(dòng)態(tài)模塊
    2.定位C/C++導(dǎo)出模塊初始化函數(shù)是目,名字為init+dllmodule
    3.執(zhí)行這個(gè)初始化函數(shù)妹萨。
    4.這個(gè)是初始化函數(shù)調(diào)用函數(shù)Py_InitModule年枕,這個(gè)函數(shù)會(huì)更新sys.modules,從而將這個(gè)模塊快加入到python中乎完。

Py_InitModule函數(shù)有兩個(gè)參數(shù)熏兄,第一個(gè)為模塊名,第二個(gè)為PyMethodDef列表(或者NULL)树姨,保存模塊中的函數(shù)信息摩桶。

導(dǎo)出函數(shù)

使用PyMethodDef定義需要導(dǎo)出的函數(shù),定義格式如下:

static PyMethodDef addfuncMethods[] = {
  {"func_name", func, func_feature_flags, "function docstring"},
  {NULL} // 結(jié)束標(biāo)志
};

其中帽揪,函數(shù)指針func必須使用固定格式:

static PyObject*  func(PyObject *self, PyObject *args)

or

static PyObject*  func(PyObject *self, PyObject *args, PyObject *kwds)

func_feature_flags說明函數(shù)類型硝清,有如下幾種:

METH_VARARGS: 只使用占位參數(shù),比如f(a,b),f(a, b)
METH_KEYWORDS:包含了關(guān)鍵字參數(shù)转晰,比如f(
c), f(a,*c)
METH_NOARGS:沒有參數(shù)芦拿,比如f()
METH_STATIC對(duì)應(yīng)python中的static函數(shù),staticmethod
METH_STATIC對(duì)應(yīng)class函數(shù),classmethod

3.1 C++導(dǎo)出函數(shù)的處理過程

  1. 從args/kwds參數(shù)中提取出參數(shù)查邢,需要將python類型的參數(shù)處理為C/C++類型蔗崎。
  2. 這一步是我們想在C++層做的所有的邏輯扰藕。
  3. 將C++邏輯得到的結(jié)果轉(zhuǎn)為python類型,然后return实胸。
  4. 注意處理exceptions和引用計(jì)數(shù)/內(nèi)存泄漏他嫡。

舉例說明

static PyObject* msg_box(PyObject *self, PyObject *args) #函數(shù)聲明
{
    const char *msg;
    if (!PyArg_ParseTuple(args, "s", &msg)) #1 參數(shù)轉(zhuǎn)換
        return NULL;

    MessageBox(0, msg, "test", 0);#2 C++邏輯

    Py_INCREF(Py_None);# 4引用計(jì)數(shù)
    return Py_None; # 3 return python類型結(jié)果
}

提取占位參數(shù)

提取占位參數(shù),使用函數(shù)PyArg_ParseTuple(PyObject *args, char *format, ...)
比如PyArg_ParseTuple(args, "sbi", &argStr, &argChar, &argInt)庐完,args包含三個(gè)參數(shù)钢属,分別是string(char *),char和int型门躯,轉(zhuǎn)換后C++使用對(duì)應(yīng)類型的變量保存淆党。

Paste_Image.png

關(guān)鍵字參數(shù)使用函數(shù)PyArg_ParseTupleAndKeywords,使用方式類似讶凉。

函數(shù)返回值

python的函數(shù)一定有返回值的染乌,所以導(dǎo)出給python用的C++函數(shù)也必須有返回值,沒有也要返回Py_None懂讯。
此外荷憋,函數(shù)的返回值類型必須為PyObject 。為了達(dá)到這個(gè)目的褐望,需要將返回的結(jié)果轉(zhuǎn)為python類型勒庄,可以使用Py_BuildValue()/PyInt_From()/PyString_From*()/..等函數(shù)轉(zhuǎn)換串前,這些函數(shù)生成的函數(shù)對(duì)象,可以直接返回表实蔽,不需要加引用荡碾。

引用計(jì)數(shù)

非常重要,可能導(dǎo)致引用泄露導(dǎo)致內(nèi)存泄漏局装,也可以能減多了坛吁,在某一個(gè)對(duì)象正在被管理的情況下,這個(gè)對(duì)象已被釋放或者被指向錯(cuò)了铐尚。

Py_INCREAF/Py_DECREF 手動(dòng)加減引用計(jì)數(shù)拨脉。

New Reference(Owned Reference)
Borrowed Reference
Steal Reference

每個(gè)函數(shù)必須要以NewReference返回結(jié)果。

要看一個(gè)API是borrowed reference還是new reference塑径,若borrowed女坑,返回前要increase

異常和異常處理

調(diào)用Python C API錯(cuò)誤,則API會(huì)設(shè)置異常并且返回一個(gè)錯(cuò)誤標(biāo)志统舀。我們調(diào)用了API后必須檢查錯(cuò)誤標(biāo)記匆骗,只需要return it(類比stack),不需要設(shè)置異常誉简。

若我們希望自己raise一個(gè)異常碉就,則必須自己設(shè)置exception,并且返回錯(cuò)誤比較值闷串。
設(shè)置異常:PyErr_Set*()瓮钥,設(shè)置后最終保存在sys.exc_type, sys.exc_value, sys.exc_traceback
調(diào)用API后發(fā)生了異常,但是我們自己處理掉了烹吵,這時(shí)需要清空異常:PyErr_Clear()
檢查現(xiàn)在是否有一個(gè)異常正在發(fā)生:PyErr_Occurred()

假如現(xiàn)在有一個(gè)未處理的異常碉熄,這時(shí)若我們主動(dòng)去再次設(shè)置異常,則會(huì)覆蓋肋拔。(這其實(shí)是不對(duì)的)

若有一個(gè)異常發(fā)生锈津,但是我們并沒有處理,也沒有return到上層:異常被保留凉蜂,并且在任何一個(gè)API調(diào)用時(shí)琼梆,都會(huì)拋出一個(gè)異常。
A函數(shù)拋了個(gè)異常窿吩,但是沒有處理也沒有return茎杂,A函數(shù)調(diào)用后我們又調(diào)用了B,則B會(huì)拋異常纫雁,但是這個(gè)異常其實(shí)是A的煌往。

若只return了錯(cuò)誤標(biāo)記,但是沒有處理異常:vm會(huì)知道轧邪,并且會(huì)提示(有異常發(fā)生刽脖,但是vm不知道發(fā)生了什么)悼粮。

錯(cuò)誤標(biāo)記是什么:
若函數(shù)返回PyObject*, 則將NULL作為錯(cuò)誤碼曾棕。
若返回int,則返回0/-菜循。
1

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末翘地,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子癌幕,更是在濱河造成了極大的恐慌衙耕,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,997評(píng)論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件勺远,死亡現(xiàn)場(chǎng)離奇詭異橙喘,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)胶逢,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,603評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門厅瞎,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人初坠,你說我怎么就攤上這事和簸。” “怎么了碟刺?”我有些...
    開封第一講書人閱讀 163,359評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵锁保,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我半沽,道長(zhǎng)爽柒,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,309評(píng)論 1 292
  • 正文 為了忘掉前任者填,我火速辦了婚禮浩村,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘幔托。我一直安慰自己穴亏,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,346評(píng)論 6 390
  • 文/花漫 我一把揭開白布重挑。 她就那樣靜靜地躺著嗓化,像睡著了一般。 火紅的嫁衣襯著肌膚如雪谬哀。 梳的紋絲不亂的頭發(fā)上刺覆,一...
    開封第一講書人閱讀 51,258評(píng)論 1 300
  • 那天,我揣著相機(jī)與錄音史煎,去河邊找鬼谦屑。 笑死驳糯,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的氢橙。 我是一名探鬼主播酝枢,決...
    沈念sama閱讀 40,122評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼悍手!你這毒婦竟也來了帘睦?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,970評(píng)論 0 275
  • 序言:老撾萬榮一對(duì)情侶失蹤坦康,失蹤者是張志新(化名)和其女友劉穎竣付,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體滞欠,經(jīng)...
    沈念sama閱讀 45,403評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡古胆,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,596評(píng)論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了筛璧。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片逸绎。...
    茶點(diǎn)故事閱讀 39,769評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖隧哮,靈堂內(nèi)的尸體忽然破棺而出桶良,到底是詐尸還是另有隱情,我是刑警寧澤沮翔,帶...
    沈念sama閱讀 35,464評(píng)論 5 344
  • 正文 年R本政府宣布陨帆,位于F島的核電站,受9級(jí)特大地震影響采蚀,放射性物質(zhì)發(fā)生泄漏疲牵。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,075評(píng)論 3 327
  • 文/蒙蒙 一榆鼠、第九天 我趴在偏房一處隱蔽的房頂上張望纲爸。 院中可真熱鬧,春花似錦妆够、人聲如沸识啦。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,705評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)颓哮。三九已至,卻和暖如春鸵荠,著一層夾襖步出監(jiān)牢的瞬間冕茅,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,848評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留姨伤,地道東北人哨坪。 一個(gè)月前我還...
    沈念sama閱讀 47,831評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像乍楚,于是被迫代替她去往敵國(guó)和親当编。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,678評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容