在实际开发过程中,由于有些经典高效的库是由C写的,尤其涉及到计算密集型的,python很难做到高效,因此我们需要实现将C库作为模块引入python,供我们使用,在这个过程里面,希望大家少踩坑
我们来以一个小demo为例,这里首先展示下demo目录结构
- demo
- -- install.sh # sh构建文件
- -- main.py # 测试文件
- -- setup.py # 构建py扩展库文件
- -- test.c # C扩展库
- python3 setup.py install
-
- rm -rf ./dist
- rm -rf ./build
- from distutils.core import setup, Extension
-
- setup(name='aaa', # 定义的模块名
- version='1.0',
- ext_modules=[
- Extension('aaa', ['test.c']) # aaa为c文件中定义的模块名,test.c为 c文件路径
- ]
- )
- #include <Python.h>
-
- //a func to calc fib numbers
- int cFib(int n)
- {
- if (n<2) return n;
- return cFib(n-1) + cFib(n-2);
- }
-
- // 实现c与py参数返回值桥接
- static PyObject* fib(PyObject* self,PyObject* args)
- {
- int n;
- if (!PyArg_ParseTuple(args,"i",&n))
- return NULL;
- return Py_BuildValue("i",cFib(n));
- }
-
- // 定义模块包含的功能/函数
- static PyMethodDef module_methods[] = {
- {"fib",(PyCFunction) fib, METH_VARARGS,"calculates the fibonachi number"},
- {NULL,NULL,0,NULL}
- };
-
- // 封装一个模块结构体
- static struct PyModuleDef aaa =
- {
- PyModuleDef_HEAD_INIT,
- "aaa", /* name of module */
- "", /* module documentation, may be NULL */
- -1, /* size of per-interpreter state of the module, or -1 if the module keeps state in global variables. */
- module_methods
- };
-
- // init该模块为py模块
- PyMODINIT_FUNC PyInit_aaa(void)
- {
- return PyModule_Create(&aaa);
- }
- import aaa
-
- if __name__ == '__main__':
-
- for num in range(10):
- print(aaa.fib(num))
-
需要注意的是,你期待生成的模块名需与c文件中几个关键的名称须保持一致
也就是以上例子中setup.py和test.c中所有为aaa的地方
以上文件准备好后,开始打包
首先进入demo目录
- cd demo
执行构建sh文件
- install.sh
不报错即构建成功
测试:
在demo目录下执行
- python3 main.py
正常输出:
- 0
- 1
- 1
- 2
- 3
- 5
- 8
- 13
- 21
- 34
如果执行测试脚本时提示导入模块问题,例:
ImportError:The dynamic module does not define the init function
请检查期待生成的模块名需与c文件中几个关键的名称须保持一致,即以上例子中setup.py和test.c中所有为aaa的地方