成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專(zhuān)欄INFORMATION COLUMN

Python: C擴(kuò)展初體驗(yàn)

xcold / 2792人閱讀

摘要:哪怕工作中比較少機(jī)會(huì)自己寫(xiě)擴(kuò)展了解這塊的知識(shí),也有利于我們更加深入了解的運(yùn)行本質(zhì)。表示這個(gè)模塊使用這個(gè)映射表。所以,在我們編寫(xiě)擴(kuò)展時(shí),也需要時(shí)刻謹(jǐn)記這步主要會(huì)用到下面兩個(gè)宏增加引用例減少引用例不能直接使用釋放,必須使用然后即可。

前言

使用 Python 毋庸置疑減少了很多規(guī)則約束和開(kāi)發(fā)成本,讓我們能夠更加專(zhuān)注于邏輯而非語(yǔ)法。但是得此失彼,開(kāi)發(fā)效率提高了,卻帶來(lái)了運(yùn)行性能的問(wèn)題,所以就常常被其他門(mén)派追著暴打。
 
身為一個(gè) pythoner,我們也很憂傷呀,怪我們咯..

萬(wàn)幸的是,雖然上帝關(guān)掉了我們一扇門(mén),但是卻為我們打開(kāi)了另一扇窗,正因?yàn)榈讓邮怯?C語(yǔ)言 寫(xiě)的,所以我們可以將一些性能損耗比較大的功能,或者模塊,通過(guò) C語(yǔ)言 重寫(xiě),然后 import xxxx 來(lái)無(wú)縫結(jié)合。

哪怕工作中比較少機(jī)會(huì)自己寫(xiě)C擴(kuò)展, 了解這塊的知識(shí),也有利于我們更加深入了解 Python 的運(yùn)行本質(zhì)。

網(wǎng)上比較是通過(guò) ctypes 或者 setup.py 的方式實(shí)現(xiàn)引用和編譯安裝,這邊想試下最原始的方法~

快速開(kāi)車(chē) 1. 實(shí)現(xiàn)接口函數(shù)

接口函數(shù)是什么意思?可以簡(jiǎn)單理解成就是 PythonC 的對(duì)接函數(shù),舉個(gè)栗子:

static PyObject *test(PyObject *self, PyObject *args){
    int arg1, arg2;
    if(!(PyArg_ParseTuple(args, "ii", &arg1, &arg2))){
        return NULL;
    }
    return Py_BuildValue("i",  arg1 + arg2 * 10);
}

我們可以看到這個(gè)函數(shù)和傳統(tǒng)意義上的 C 用法用點(diǎn)不同了,特別是在函數(shù)形參那邊的PyObject self, PyObject args

第一個(gè)參數(shù)是 PyObject *self,這個(gè)參數(shù)是Python內(nèi)部使用的,可以不用管;

第二個(gè)參數(shù)是 PyObject *args,這個(gè)參數(shù)非常重要,因?yàn)檫@個(gè)攬括了所有傳給函數(shù)的參數(shù)。它是一個(gè)參數(shù)列表,把所有的參數(shù)都整合到

一個(gè) string, 因此,如果我們需要解析這些參數(shù)需要用特定的姿勢(shì)!我們需要用到 PyArg_ParseTuple 來(lái)解開(kāi)這個(gè)扣人心弦的入口!

PyArg_ParseTuple 函數(shù)說(shuō)明:

args就是需要轉(zhuǎn)換的參數(shù);

ii 就是參數(shù)類(lèi)型的格式符號(hào),這里代表 int init;(更多類(lèi)型請(qǐng)看官網(wǎng):https://docs.python.org/2/c-a...)

后面的 &arg1, &arg2 就是通過(guò)參數(shù)解析提取的值,存放的地方,這有點(diǎn)類(lèi)似 C 的 scanf;

很明顯,這三個(gè)參數(shù),在數(shù)量上存在這一定的聯(lián)系,也就是,傳進(jìn)去兩個(gè) int參數(shù),那么就肯定是對(duì)應(yīng)了兩個(gè) ii,然后就會(huì)對(duì)應(yīng)存在 兩個(gè)實(shí)際的"容器"內(nèi),這里要注意,一不小心就會(huì) Segmentation fault

對(duì)應(yīng)有解析參數(shù)的,肯定也有 C模塊 值轉(zhuǎn)換成 Python對(duì)象 的,那就是 Py_BuildValue。

Py_BuildValue 函數(shù)說(shuō)明:

# 對(duì)比著來(lái)看
PyArg_ParseTuple(args, "ii", &arg1, &arg2)    Python -> C模塊
Py_BuildValue("i",  arg1 + arg2 * 10);        C 模塊 -> Python

第一個(gè)參數(shù) 和 PyArg_ParseTuple 的第二個(gè)參數(shù)一樣,都是格式化符號(hào);

第二個(gè)參數(shù)是需要轉(zhuǎn)換的參數(shù),函數(shù) Py_BuildValue 會(huì)把所有的返回指都組裝成 tuplePython

相關(guān)的官方文檔:https://docs.python.org/2/c-a...

2. 定義方法列表
# 示例
static PyMethodDef  testMethods[] = {
    {"test", test, METH_VARARGS, "This is test"},
    {NULL, NULL, 0, NULL}
};

PyMethodDef 是一個(gè) C結(jié)構(gòu)體,用來(lái)完成一個(gè)映射,也就是便于方法查找,我們把需要被外面調(diào)用的方法都記錄在這表內(nèi)。

PyMethodDef 結(jié)構(gòu)體成員說(shuō)明:

第一個(gè)字段:在 Python 里面使用的方法名;

第二個(gè)字段:C 模塊內(nèi)的函數(shù)名;

第三個(gè)字段:方法參數(shù)類(lèi)型,是無(wú)參數(shù)(METH_NOARGS) , 還是有位置參數(shù)(METH_VARARGS), 還是其他等等;

第四個(gè)字段:方法描述,就是通過(guò) help() 或者 doc 可以看到的;

需要注意的是,這個(gè)列表的最后必須以 {NULL, NULL, 0, NULL} 的形式來(lái)代表聲明結(jié)束,也有一些大佬用 {NULL, NULL},不過(guò)個(gè)人覺(jué)得寫(xiě)完整也不會(huì)累到哪去, 相反會(huì)比較直觀。

# PyMethodDef 結(jié)構(gòu)體定義源碼, 取自 Python2.7 Include/methodobject.h
struct PyMethodDef {
    const char  *ml_name;   /* The name of the built-in function/method */
    PyCFunction  ml_meth;   /* The C function that implements it */              
    int      ml_flags;     /* Combination of METH_xxx flags, which mostly 
                              describe the args expected by the C func */
    const char  *ml_doc;    /* The __doc__ attribute, or NULL */
};

正因?yàn)榇嬖谶@樣的一份記錄表,Python 才能夠?qū)ふ业较鄳?yīng)的函數(shù)

同樣的,如果我們想要找一個(gè)模塊的 Python 函數(shù) 對(duì)應(yīng)什么的 C模塊方法,也能通過(guò)這地方比較粗暴得知,例如 Python 的 list

# 取自 Python2.7 object/listobject.c
static PyMethodDef list_methods[] = {
    {"__getitem__", (PyCFunction)list_subscript, METH_O|METH_COEXIST, getitem_doc},
    {"__reversed__",(PyCFunction)list_reversed, METH_NOARGS, reversed_doc},
    {"__sizeof__",  (PyCFunction)list_sizeof, METH_NOARGS, sizeof_doc},
    {"append",          (PyCFunction)listappend,  METH_O, append_doc},
    {"insert",          (PyCFunction)listinsert,  METH_VARARGS, insert_doc},
    {"extend",      (PyCFunction)listextend,  METH_O, extend_doc},
    {"pop",             (PyCFunction)listpop,     METH_VARARGS, pop_doc},
    {"remove",          (PyCFunction)listremove,  METH_O, remove_doc},
    {"index",           (PyCFunction)listindex,   METH_VARARGS, index_doc},
    {"count",           (PyCFunction)listcount,   METH_O, count_doc},
    {"reverse",         (PyCFunction)listreverse, METH_NOARGS, reverse_doc},
    {"sort",            (PyCFunction)listsort,    METH_VARARGS | METH_KEYWORDS, sort_doc},
    {NULL,              NULL}           /* sentinel */
};
3. 實(shí)現(xiàn)初始化函數(shù) (關(guān)鍵)
PyMODINIT_FUNC inittest(){
    Py_InitModule("test", testMethods);
}

需要特別注意的是,這個(gè)函數(shù)名不能像上面那樣,這是有規(guī)定的,必須是 init + 模塊名字,比方說(shuō),我的最后編譯出來(lái)的文件是 test.so, 那我的函數(shù)名就是 inittest, 這樣在 Python 導(dǎo)入 test 模塊時(shí),才能找到這個(gè)函數(shù)并調(diào)用。

這里調(diào)用了 Py_InitModule 函數(shù)來(lái)將模塊名字和映射表結(jié)合在一起。表示 test 這個(gè)模塊使用 testMethods 這個(gè)映射表。

4. 注意對(duì)象引用管理和內(nèi)存泄露

Python 在對(duì)象管理、內(nèi)存管理上面,有引用計(jì)數(shù),標(biāo)記-清除分代回收等策略,其中引用計(jì)數(shù)發(fā)生的頻率會(huì)非常非常高,依賴這個(gè)通常已經(jīng)能夠解決大部分的對(duì)象殘留問(wèn)題了。

所以,在我們編寫(xiě) C擴(kuò)展 時(shí),也需要時(shí)刻謹(jǐn)記這步.

主要會(huì)用到下面兩個(gè)宏:

1. 增加引用: Py_INCREF    例: Py_INCREF(pObj1)
2. 減少引用: Py_DECREF    例: Py_DECREF(pObj1)

不能直接使用 free/delete 釋放,必須使用 Py_DECREF(pObj1), 然后 pObj1 = NULL 即可。

具體可以參考:
官網(wǎng):https://docs.python.org/2/ext...
垃圾回收機(jī)制: http://www.wklken.me/posts/20...

編譯導(dǎo)出
gcc  -I /usr/include/python2.7/ -fpic --shared -o test.so test.c
完整例子

test.c

#include
static PyObject *test(PyObject *self, PyObject *args){
    int arg1, arg2;
    if(!(PyArg_ParseTuple(args, "ii", &arg1, &arg2))){
        return NULL;
    }
    return Py_BuildValue("i",  arg1 + arg2 * 10);
}

static PyMethodDef  testMethods[] = {
    {"test", test, METH_VARARGS, "This is test"},
    {NULL, NULL}
};

PyMODINIT_FUNC inittest(){
    Py_InitModule("test", testMethods);
}

test.py

import test
print test.test(1, 2)   # 輸出 21

歡迎各位大神指點(diǎn)交流, QQ討論群: 258498217
轉(zhuǎn)載請(qǐng)注明來(lái)源: https://segmentfault.com/a/11...

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/42055.html

相關(guān)文章

  • WebAssembly 體驗(yàn):從零開(kāi)始重構(gòu)計(jì)算模塊

    摘要:初體驗(yàn)從零開(kāi)始重構(gòu)計(jì)算模塊從屬于筆者的前端入門(mén)與工程實(shí)踐,更多相關(guān)資料文章參考學(xué)習(xí)與實(shí)踐資料索引和學(xué)習(xí)與實(shí)踐資料索引。不過(guò)筆者也只是了解其概念而未真正付諸實(shí)踐,本文即是筆者在將我司某個(gè)簡(jiǎn)單項(xiàng)目中的計(jì)算模塊重構(gòu)為過(guò)程中的總結(jié)。 WebAssembly 初體驗(yàn):從零開(kāi)始重構(gòu)計(jì)算模塊從屬于筆者的 Web 前端入門(mén)與工程實(shí)踐,更多相關(guān)資料文章參考WebAssembly 學(xué)習(xí)與實(shí)踐資料索引和 ...

    netmou 評(píng)論0 收藏0
  • Python 體驗(yàn)

    摘要:廣告歡迎大家到路飛學(xué)城學(xué)習(xí)很喜歡薪時(shí)代這個(gè)詞所以我們要擁抱人工智能擁抱前提下載,如果是電腦會(huì)自帶。 廣告:歡迎大家到 路飛學(xué)城 學(xué)習(xí) Python~ 很喜歡 Python 薪時(shí)代 這個(gè)詞~所以我們要擁抱 人工智能~擁抱 Python~ 前提:下載 Python,如果是 Mac 電腦會(huì)自帶 Python。 Hello World! Mac 電腦打開(kāi)終端輸入: cd desktop tou...

    roundstones 評(píng)論0 收藏0
  • Django 項(xiàng)目配置體驗(yàn)(一)

    摘要:靜態(tài)資源路徑可以有多個(gè),所以這里使用一個(gè)列表進(jìn)行配置再次進(jìn)入,完美后記現(xiàn)在只涉及到了項(xiàng)目的配置和一些基礎(chǔ)的配置,沒(méi)有涉及到請(qǐng)求從開(kāi)始到完成的任何內(nèi)容。下篇教程將集中進(jìn)行記錄。 前言 推薦使用 virtualenv 創(chuàng)建 python 虛擬環(huán)境,防止因?yàn)槭褂?pip 安裝依賴到全局引起版本沖突的問(wèn)題,PyCharm 默認(rèn)會(huì)生成一個(gè) venv 目錄并創(chuàng)建虛擬環(huán)境,使用 IDE 自帶的終端...

    Wildcard 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<