【python】简单的C扩展模块

描述

使用Python的扩展API编写一些简单的C扩展模块,扩展模块的计算性能和C/C++同级别的。

  • 本文针对一个简单的C语言扩展程序进行展开

环境

测试环境:

  • Centos 7.4 x86_64
  • gcc version 4.8.5
  • Python 3.6.8

扩展模块的设计流程

  1. 引入必要头文件:以python.h为主的几个常用头文件
  2. 接口文件:负责C语言与Python之间的语言交互
  3. 编写setup.py:配置扩展模块元信息的脚本
头文件和C语言程序

头文件名为sample.h,具体内容如下

/* 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);

C语言程序sample.c,其内容如下

/* sample.c */
#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;
}

把标准C文件编译成标准动态库,即libsamplpe.so

gcc -shared -fPIC sample.c -o libsample.so
# 该操作没有任何意义,只是为了证明C语言文件正确
接口文件

pysample.c是负责C语言与Python之间的语言交互,负责在两个环境中作数值转换的代码。
某种程度上pysample.c更像是接口,就像头文件对于标准C文件一样。
pysample.c文件内容如下:

#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_FUNC
PyInit_sample(void) {
  return PyModule_Create(&samplemodule);
}
编写setup.py文件

setup.py文件内容如下

# setup.py
from distutils.core import setup, Extension

setup(name='sample',
      ext_modules=[
        Extension('sample',
                  ['sample.c', 'pysample.c'],
                  include_dirs = ['sample'],
                  )
        ]
)

编辑完setup.py文件之后,输入命令

python3 setup.py build_ext --inplace

查看编译之后的结果
在这里插入图片描述
编译之后会生成sample.cpython-36m-x86_64-linux-gnu.so动态链接库,也就是扩展模块

测试

编辑测试文件example.py,内容如下

import sample
print(sample.gcd(35,42))
print(sample.in_mandel(0,0,500))
print(sample.in_mandel(2.0,1.0,500))
print(sample.divide(42,8))

运行

python3 example.py

运行结果

[root@dev m2]# python3 example.py
7
1
0
(5, 2)

谈谈python setup.py install

python setup.py install包括两步:

python setup.py build
python setup.py install

这两步可以分开执行,也可以只执行python setup.py install,因为python setup.py install总是会先buildinstall

python setup.py buildpython编译module的过程,最后会生成build文件夹。build之后的install过程就是复制build/lib文件到用户指定的lib库。

参考文献:

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值