python3调用及封装并调用c程序

1 篇文章 0 订阅

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
请输入整数值:2001200累加的计算结果为20100
总共用时0.00023293495178222656
[root@bogon test1]# python3 python_add.py
请输入整数值:2001200累加的计算结果为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程序

上边第一个代码就是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

#include <stdio.h>
  
void my_add(int num) {
    long int result = 0;
    for(long int i = 1; i <= num; i++) {
        result += i;
    }

    printf("从1到%d累加的计算结果为%ld\n",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
请输入整数值:2001200累加的计算结果为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 <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);
}

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 <Python.h>
#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 = %d\n",n0);
        printf("n1 = %d\n",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 <Python.h>需要安装python3-devel

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值