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

歡迎訪問 生活随笔!

生活随笔

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

python

python基础-C扩展

發布時間:2023/12/9 python 22 豆豆
生活随笔 收集整理的這篇文章主要介紹了 python基础-C扩展 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

寫python的c擴展簡介
使用C/C++編寫Python模塊擴展
Python - 用C擴展編程
使用 C 或 C++ 擴展 Python

原因

  • 添加額外的非python功能。
  • 性能瓶頸的效率提升
  • 專有源代碼保密

寫擴展庫的代碼

Extest.c文件包含包含要擴展的C模塊,包含fac()和reverse()函數。
并調試完bug。

#include <stdio.h> #include <stdlib.h> #include <string.h>int fac(int n) {if (n<2) return 1;return n * fac(n-1); }char * reverse(char *s) {register char t, *p = s, *q = s+(strlen(s)-1);while(p<q){t = *p;*p++ = *q;*q-- = t;}return s; }int test() {char s[255];printf("4! == %d\n", fac(4));printf("8! == %d\n", fac(8));printf("12! == %d\n", fac(12));strcpy(s, "abcdef");printf("reversing 'abcdef', we get '%s'\n",reverse(s));strcpy(s, "madam");printf("reversing 'madam', we get '%s'\n",reverse(s));return 0; }

包裝代碼

  • 包含python頭文件
  • 為每個模塊的每個函數增加一個Pyobject * Module_func()的包裝函數
  • 為每個模塊增加一個PyMethodDef ModuleMethods[]的數組
  • 增加木塊初始化函數void initModule()

為想被Python環境訪問的函數增加一個靜態變量,函數的返回值類型為PyObject*,函數名前要加上模塊名和一個下劃線。比如Extest模塊的fac函數,創建包裝函數Extest_fac()。這樣可以在python中import Extest,然后調用Extest.fac()。

包裝函數就是把Python的值傳遞給C,然后調用C函數處理。當處理完成返回給python的時候,把函數的計算結果轉換成python對象,返回給python。

從python到C的轉換用PyArg_Parse*系列函數。從C轉到python的時候,就用Py_BuildValue()函數。

PyArg_Parse系列函數用法跟C的sscanf 函數很像,接受一個字符串流,根據一個指定格式字符串進行解析,把結果放入到相應的指針所指的變量中。返回值為1表示解析成功,返回值為0表示失敗。
Py_BuildValue的用法跟sprintf函數很像,把所有的參數按格式字符串所指定的格式轉換成一個python對象。

函數描述
int PyArg_ParseTuple()把python傳過來的參數轉為C
int PyArg_ParseTupleAndKeywords()把python傳過來的參數轉為C,但是同時解析關鍵字參數
PyObject *Py_BuildValue()把C的數據轉為python的一個對象或一組對象,然后返回

python和C數據轉換的格式符號

format codepython typec type
sstrchar *
zstr/Nonechar * /NULL
iintint
llonglong
cstrchar
dfloatdouble
DcomplexPy_Complex *
O(any)PyObject *
SstrPyStringObject
// 包裝函數 static PyObject * Extest_fac(PyObject * self, PyObject * args) {int res;int num;PyObject * retval;res = PyArg_ParseTuple(args, "i", &num);if (!res){return NULL;}res = fac(num);retval = Py_BuildValue("i", res);return retval; }static PyObject * Extest_doppel(PyObject *self, PyObject * args) {char * orig_str;char * dupe_str;PyObject * retval;if(!PyArg_ParseTuple(args, "s", $orig_str)) return NULL;retval = Py_BuildValue("ss", orig_str, dupe_str=reverse(strdup(orig_str)));free(dupe_str);return retval; }static PyObject * Extest_test(PyObject * self, PyObject *args) {test();return Py_BuildValue(""); }

‘ss’格式讓Py_BuildValue()函數生成了一個包含兩個字符串的tuple。

C代碼中注意內存泄露。復制字符串后在函數退出前要釋放。
為每個模塊增加PyMethodDef ModuleMethods[]數組
完成包裝函數后,需要把函數列在某個地方,編譯python解釋器能夠導入并調用。
這是個二維數組,里面每個數組包含一個函數,最后放一個NULL數組表示列表的結束。

// 模塊的方法數組PyMethodDef ModuleMethods[] //METH_VARARGS常量表示參數以tuple形式傳入.如果使用PyArg_ParseTupleAndKeywords()函數解析命名 //參數需要使用METH_VARARGS與METH_KEYWORDS常量進行邏輯與運算。 static PyMethodDef ExtestMethods[]{{"fac", Extest_fac, METH_VARARGS},{"doppel", Extest_doppel, METH_VARARGS},{'test', Extest_test, METH_VARARGS}{NULL, NULL}, }

增加模塊初始換函數void initModule()
調用Py_InitModule()函數,并把模塊名和ModuleMethods[]數組的名字穿進去。

//增加模塊初始化函數void initModule() void initExtest() {Py_InitModule("Extest", ExtestMethods); }

編譯

  • 創建setup.py
  • 通過運行setup.py來編譯和連接代碼
  • 從python中導入擴展模塊

創建setup.py,編譯主要由setup()函數完成。這個函數調用之前的所有代碼。每個擴展模塊需要一個Extension實例。
Extension(MOD,sources=['Extest.c'])
名字為模塊名,sources參數是所有源代碼的文件列表。
setup()函數第一個參數表示要編譯哪些東西,一個列表列出要編譯的對象。

from distutils.core import setup, ExtensionMOD = 'Extest' setup(name=MOD, ext_modules=[Extension(MOD,sources=['Extest.c'])])

編譯和連接代碼
運行setup.py build命令可以開始編譯我們的擴展了。

$python setup.py build

導入和測試
擴展會被創建在運行setup.py腳本所在的目錄下的build/lib.*目錄下。可以切換到哪個目錄中測試新木塊,也可以使用命令安裝到python中

$python setup.py install

然后就可以在python中導入和使用模塊中的函數了。

總結

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

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