python3调用及封装并调用c程序
一、python3直接调用c程序二、python3封装后以模块的形式调用c程序
python3调用及封装并调用c程序首先,我们来看一个示例:
导入c程序实现:
import time
from ctypes import *
def main():
num = int(input("请输入整数值:"))
result = 0
start_time = time.time()
result = cdll.LoadLibrary("./add.so")
result.my_add(num)
end_time = time.time()
print("总共用时%s"%(end_time-start_time))
if __name__ == "__main__":
main()
纯python实现
import time
def main():
num = int(input("请输入整数值:"))
result = 0
start_time = time.time()
for i in range(num+1):
result += i
print("从1到%d累加的计算结果为%d"%(num,result))
end_time = time.time()
print("总共用时%s"%(end_time-start_time))
if __name__ == "__main__":
main()
执行结果对比
[root@bogon test1]# python3 c_add.py 请输入整数值:200 从1到200累加的计算结果为20100 总共用时0.00023293495178222656 [root@bogon test1]# python3 python_add.py 请输入整数值:200 从1到200累加的计算结果为20100 总共用时7.748603820800781e-05 [root@bogon test1]# vim c_add.py [root@bogon test1]# vim python_add.py
可以很清晰的看到 c运算的时间和python运算时间对比结果。
c与python对比:python不擅长"大量运算"任务,python程序优势在于:编写简单,适合"IO密集型作业"(比如打开文件,下载图片,运行脚本)。python快速实现"计算密集型作业"的方法就是"把c的代码拿过来直接用"。
上边第一个代码就是python3直接调用c程序的示例,步骤一共分四步,让我们一起实现一下:
四步:
1.将.c后缀的文件编译为动态库文件(.so结尾)
gcc 原文件名.c -shared -o 新文件名.so 或者 gcc 原文件名.c -shared -o test.so -I/usr/include/python3.6m -fPIC -lpython3 示例 以将test.c编译为test.so为例 gcc test.c -shared -o test.so
2.在python文件中导入头文件
from ctypes import *
3.在python中引入c动态库,并用变量接收动态库的引用
格式:
变量名 = cdll.LoadLibrary("动态库文件路径")
示例:
result = cdll.LoadLibrary("./add.so")
4.调用动态库方法
格式: 动态库引用.库函数(参数) 示例: result.my_add(num)
实现示例:
1.准备c程序add.c
#includevoid my_add(int num) { long int result = 0; for(long int i = 1; i <= num; i++) { result += i; } printf("从1到%d累加的计算结果为%ldn",num,result); }
编译成 so库文件:
gcc add.c -shared -o add.so
2.python3代码实现:
import time
#引入
from ctypes import *
def main():
num = int(input("请输入整数值:"))
result = 0
start_time = time.time()
#直接导入库文件
result = cdll.LoadLibrary("./add.so")
#调用方法
result.my_add(num)
end_time = time.time()
print("总共用时%s"%(end_time-start_time))
if __name__ == "__main__":
main()
执行python3 c_add.py
[root@bogon test1]# python3 c_add.py 请输入整数值:200 从1到200累加的计算结果为20100 总共用时0.00023293495178222656二、python3封装后以模块的形式调用c程序
我们来以一个小demo为例,这里首先展示下demo目录结构
demo -- install.sh # sh构建文件 -- main.py # 测试文件 -- setup.py # 构建py扩展库文件 -- add.c # C扩展库
install.sh
python3 setup.py install rm -rf ./dist rm -rf ./build
setup.py
封装启动文件
from distutils.core import setup, Extension
setup(name='aaa', # 定义的模块名
version='1.0',
ext_modules=[
Extension('aaa', ['./add.c']) # aaa为c文件中定义的模块名,add.c为c文件路径
]
)
test.c
简单的fib函数封装,以下内容为python3的封装方式,python2可自行百度
#include//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", "", -1, module_methods }; // init该模块为py模块 PyMODINIT_FUNC PyInit_aaa(void) { return PyModule_Create(&aaa); }
main.py
用于测试c扩展库是否构建成功
import aaa
if __name__ == '__main__':
for num in range(10):
print(aaa.fib(num))
需要注意的是,你期待生成的模块名需与c文件中几个关键的名称须保持一致,PyModuleDef结构体里,setup里
以上文件准备好后,进入目录进行测试
执行构建sh文件
[root@bogon test2]# ./install.sh running install running build running build_ext building 'aaa' extension creating build creating build/temp.linux-loongarch64-3.6 loongarch64-loongson-linux-gnu-gcc -pthread -Wno-unused-result -Wsign-compare -DNDEBUG -O2 -g -D_GNU_SOURCE -fPIC -fwrapv -O2 -g -D_GNU_SOURCE -fPIC -fwrapv -O2 -g -D_GNU_SOURCE -fPIC -fwrapv -fPIC -I/usr/include/python3.6m -c ./add.c -o build/temp.linux-loongarch64-3.6/./add.o creating build/lib.linux-loongarch64-3.6 loongarch64-loongson-linux-gnu-gcc -pthread -shared -Wl,-z,relro -Wl,-z,now -g -Wl,-z,relro -Wl,-z,now -g build/temp.linux-loongarch64-3.6/./add.o -L/usr/lib64 -lpython3.6m -o build/lib.linux-loongarch64-3.6/aaa.cpython-36m-loongarch64-linux-gnu.so running install_lib copying build/lib.linux-loongarch64-3.6/aaa.cpython-36m-loongarch64-linux-gnu.so -> /usr/local/lib64/python3.6/site-packages running install_egg_info Removing /usr/local/lib64/python3.6/site-packages/aaa-1.0-py3.6.egg-info Writing /usr/local/lib64/python3.6/site-packages/aaa-1.0-py3.6.egg-info
不报错即构建成功
测试:
[root@bogon test2]# 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的地方
两个c和头文件的情况下的封装
c程序test_add.c
#include "test.h"
int add(int a,int b)
{
return a+b;
}
头文件test.h
int add(int a,int b);
c的扩展程序test_add_py.c,只适用于python3
#include#include "test.h" PyObject* wrap_add(PyObject* self, PyObject* args) { int n0,n1, result; if (!PyArg_ParseTuple(args, "ii", &n0, &n1)) return NULL; printf("n0 = %dn",n0); printf("n1 = %dn",n1); result = add(n0,n1); return Py_BuildValue("i", result); } static PyMethodDef testMethods[] = { {"add", wrap_add, METH_VARARGS, "Add"}, {NULL, NULL} }; static struct PyModuleDef test = { PyModuleDef_HEAD_INIT, "test", NULL, -1, testMethods}; PyMODINIT_FUNC PyInit_test(void) { return PyModule_Create(&test); }
编译
gcc -fPIC -shared -o test.so -I/usr/include/python3.6m test_add.c test_add_py.c -lpython3
测试main.py
import test
if __name__ == '__main__':
print(test.add(2,4))
执行
[root@bogon test2]# python3 main.py n0 = 2 n1 = 4 6
引用#include



