编写Python3的C扩展

为何要编写C扩展

  • 保护核心代码
  • 解决性能瓶颈
  • 创建C一些特有的东西

环境:

  • Linux .13.9-300.fc27.x86_64
  • Python 3.6.3

开始

目标

这次我么来实习制作Python3的扩展,实现两个功能:

  • 求一个整数的绝对值
  • 求一个字符串的逆序

用c实现这个功能:

int my_abs(int n){
    if(n<0)
        n = n * -1;
    return n;
}

void my_reverse(char *s){
    if(s){
        int len = strlen(s);
        int i;
        char t;
        for(int i= 0;i<(len-1)/2;i++){
            t = s[i];
            s[i] = s[len-1-i];
            s[len-1-i] = t;
        }
    }  
}

利用样板来包装函数

//作用,接受python传的值,将结果计算后转为Python对象返回给python
//返回类型PyObject*,函数名:模块名_函数名
static PyObject *Extest_abs(PyObject *self,PyObject *args){
    int num;
    if(!(PyArg_ParseTuple(args,"i",&num))){ //获取Python传递的参数
        return NULL;
    }
    return (PyObject*)Py_BuildValue("i",my_abs(num));//将结果转换为Python类型并返回
}

static PyObject *Extest_reverse(PyObject *self,PyObject *args){
    char *s;
    if(!(PyArg_ParseTuple(args,"z",&s))){
        return NULL;
    }
    my_reverse(s);
    return (PyObject*)Py_BuildValue("s",s);
}

为每个模块增加PyMethodDef ModuleMethods[]数组

static PyMethodDef ExtestMethods[] = {
    {"abs",Extest_abs,METH_VARARGS},//函数名,包装函数名,解析
    {"reverse",Extest_reverse,METH_VARARGS},
    {NULL,NULL},//作为结束
};

编写初始化函数

static struct PyModuleDef ExtestModule = {
    PyModuleDef_HEAD_INIT,//默认
    "Extest",//模块名
    NULL,
    -1,
    ExtestMethods //上面的数组
};

void PyInit_Extest(){
    PyModule_Create(&ExtestModule);
}

总览

my_extend.c

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<Python.h>

int my_abs(int n){
    if(n<0)
        n = n * -1;
    return n;
}

void my_reverse(char *s){
    if(s){
        int len = strlen(s);
        int i;
        char t;
        for(i= 0;i<(len-1)/2;i++){
            t = s[i];
            s[i] = s[len-1-i];
            s[len-1-i] = t;
        }
    }

}

void test(void){
    printf("test my_abs:\n");
    printf("|-8590|=%d\n",my_abs(-8590));
    printf("|-0|=%d\n",my_abs(-0));
    printf("|5690|=%d\n",my_abs(-5690));

    printf("test my_reverse:\n");
    char s0[10] = "apple";
    char s1[20] = "I love you!";
    char *s2 = NULL;
    my_reverse(s0);
    my_reverse(s1);
    my_reverse(s2);
    printf("'apple' reverse is '%s'\n",s0);
    printf("'I love you!' reverse is '%s'\n",s1);
    printf("null reverse is %s\n",s2);
}

//作用,接受python传的值,将结果计算后转为Python对象返回给python
//返回类型PyObject*,函数名:模块名_函数名
static PyObject *Extest_abs(PyObject *self,PyObject *args){
    int num;
    if(!(PyArg_ParseTuple(args,"i",&num))){
        return NULL;
    }
    return (PyObject*)Py_BuildValue("i",my_abs(num));
}

static PyObject *Extest_reverse(PyObject *self,PyObject *args){
    char *s;
    if(!(PyArg_ParseTuple(args,"z",&s))){
        return NULL;
    }
    my_reverse(s);
    return (PyObject*)Py_BuildValue("s",s);
}

static PyObject *Extest_test(PyObject *self,PyObject *args){
    test();
    return (PyObject*)Py_BuildValue("");
}

//为每个模块增加PyMethodDef ModuleMethods[]数组
static PyMethodDef ExtestMethods[] = {
    {"abs",Extest_abs,METH_VARARGS},
    {"reverse",Extest_reverse,METH_VARARGS},
    {"test",Extest_test,METH_VARARGS},
    {NULL,NULL},
};

static struct PyModuleDef ExtestModule = {
    PyModuleDef_HEAD_INIT,
    "Extest",
    NULL,
    -1,
    ExtestMethods
};

void PyInit_Extest(){
    PyModule_Create(&ExtestModule);
}

编写用于编译安装的脚本

setup.py

from distutils.core import setup,Extension

MOD = 'Extest' #模块名
setup(name=MOD,ext_modules=[Extension(MOD,sources=['my_extend.c'])]) #源文件名

编译安装:

python3 setup.py build #提示没有Python.h百度
python3 setup.py install

使用:

>>> import Extest
>>> Extest.test()
test my_abs:
|-8590|=8590
|-0|=0
|5690|=5690
test my_reverse:
'apple' reverse is 'elppa'
'I love you!' reverse is '!uoy evol I'
null reverse is (null)
>>> Extest.abs(-0)
0
>>> Extest.reverse("abc")
'cba'

python和c对应的类型转换参数表

这里写图片描述

Py_BuildValue的用法表

这里写图片描述

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值