簡單的C擴展模塊

阿裏雲問答 2022-01-07 21:13:14 阅读数:14

你想不依靠其他工具,直接使用Python的擴展API來編寫一些簡單的C擴展模塊。




采納答案1:
這也是一個當你面臨從Python 2 到 Python 3擴展代碼的問題。雖然Python提供了一個廣泛的編程API,實際上有很多方法來處理C的代碼。相比試圖給出對於每一個可能的工具或技術的詳細參考,我麼采用的是是集中在一個小片段的C++代碼,以及一些有代錶性的例子來展示如何與代碼交互。這個目標是提供一系列的編程模板,有經驗的程序員可以擴展自己的使用。這裏是我們將在大部分秘籍中工作的代碼:/* sample.c */_method#include <math.h> /* Compute the greatest common divisor */int gcd(int x, int y) { int g = y; while (x > 0) { g = x; x = y % x; y = g; } return g;} /* Test if (x0,y0) is in the Mandelbrot set or not */int in_mandel(double x0, double y0, int n) { double x=0,y=0,xtemp; while (n > 0) { xtemp = x*x - y*y + x0; y = 2*x*y + y0; x = xtemp; n -= 1; if (x*x + y*y > 4) return 0; } return 1;} /* Divide two numbers */int divide(int a, int b, int *remainder) { int quot = a / b; *remainder = a % b; return quot;} /* Average values in an array */double avg(double *a, int n) { int i; double total = 0.0; for (i = 0; i < n; i++) { total += a[i]; } return total / n;} /* A C data structure */typedef struct Point { double x,y;} Point; /* Function involving a C data structure */double distance(Point *p1, Point *p2) { return hypot(p1->x - p2->x, p1->y - p2->y);}這段代碼包含了多種不同的C語言編程特性。首先,這裏有很多函數比如 gcd() 和 is_mandel() 。divide() 函數是一個返回多個值的C函數例子,其中有一個是通過指針參數的方式。avg() 函數通過一個C數組執行數據聚集操作。Point 和 distance() 函數涉及到了C結構體。對於接下來的所有小節,先假定上面的代碼已經被寫入了一個名叫“sample.c”的文件中,然後它們的定義被寫入一個名叫“sample.h”的頭文件中,並且被編譯為一個庫叫“libsample”,能被鏈接到其他C語言代碼中。編譯和鏈接的細節依據系統的不同而不同,但是這個不是我們關注的。



采納答案2:
對於簡單的C代碼,構建一個自定義擴展模塊是很容易的。 作為第一步,你需要確保你的C代碼有一個正確的頭文件。例如:/* sample.h */#include <math.h>extern int gcd(int, int);extern int in_mandel(double x0, double y0, int n);extern int divide(int a, int b, int *remainder);extern double avg(double *a, int n);typedef struct Point { double x,y;} Point;extern double distance(Point *p1, Point *p2);通常來講,這個頭文件要對應一個已經被單獨編譯過的庫。 有了這些,下面我們演示下編寫擴展函數的一個簡單例子:#include "Python.h"#include "sample.h"/* int gcd(int, int) */static PyObject *py_gcd(PyObject *self, PyObject *args) { int x, y, result; if (!PyArg_ParseTuple(args,"ii", &x, &y)) { return NULL; } result = gcd(x,y); return Py_BuildValue("i", result);}/* int in_mandel(double, double, int) */static PyObject *py_in_mandel(PyObject *self, PyObject *args) { double x0, y0; int n; int result; if (!PyArg_ParseTuple(args, "ddi", &x0, &y0, &n)) { return NULL; } result = in_mandel(x0,y0,n); return Py_BuildValue("i", result);}/* int divide(int, int, int *) */static PyObject *py_divide(PyObject *self, PyObject *args) { int a, b, quotient, remainder; if (!PyArg_ParseTuple(args, "ii", &a, &b)) { return NULL; } quotient = divide(a,b, &remainder); return Py_BuildValue("(ii)", quotient, remainder);}/* Module method table */static PyMethodDef SampleMethods[] = { {"gcd", py_gcd, METH_VARARGS, "Greatest common divisor"}, {"in_mandel", py_in_mandel, METH_VARARGS, "Mandelbrot test"}, {"divide", py_divide, METH_VARARGS, "Integer division"}, { NULL, NULL, 0, NULL}};/* Module structure */static struct PyModuleDef samplemodule = { PyModuleDef_HEAD_INIT, "sample", /* name of module */ "A sample module", /* Doc string (may be NULL) */ -1, /* Size of per-interpreter state or -1 */ SampleMethods /* Method table */};/* Module initialization function */PyMODINIT_FUNCPyInit_sample(void) { return PyModule_Create(&samplemodule);}要綁定這個擴展模塊,像下面這樣創建一個 setup.py 文件:# setup.pyfrom distutils.core import setup, Extensionsetup(name='sample', ext_modules=[ Extension('sample', ['pysample.c'], include_dirs = ['/some/dir'], define_macros = [('FOO','1')], undef_macros = ['BAR'], library_dirs = ['/usr/local/lib'], libraries = ['sample'] ) ])為了構建最終的函數庫,只需簡單的使用 python3 buildlib.py build_ext --inplace 命令即可:bash % python3 setup.py build_ext --inplacerunning build_extbuilding 'sample' extensiongcc -fno-strict-aliasing -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes -I/usr/local/include/python3.3m -c pysample.c -o build/temp.macosx-10.6-x86_64-3.3/pysample.ogcc -bundle -undefined dynamic_lookupbuild/temp.macosx-10.6-x86_64-3.3/pysample.o \ -L/usr/local/lib -lsample -o sample.sobash %如上所示,它會創建一個名字叫 sample.so 的共享庫。當被編譯後,你就能將它作為一個模塊導入進來了:>>> import sample>>> sample.gcd(35, 42)7>>> sample.in_mandel(0, 0, 500)1>>> sample.in_mandel(2.0, 1.0, 500)0>>> sample.divide(42, 8)(5, 2)>>>如果你是在Windows機器上面嘗試這些步驟,可能會遇到各種環境和編譯問題,你需要花更多點時間去配置。 Python的二進制分發通常使用了Microsoft Visual Studio來構建。 為了讓這些擴展能正常工作,你需要使用同樣或兼容的工具來編譯它。 參考相應的 Python文檔

版权声明:本文为[阿裏雲問答]所创,转载请带上原文链接,感谢。 https://gsmany.com/2022/01/202201072113135917.html