Python调用C函数的方法以及如何编写Python的C扩展

01

前言

前言属闲聊,正文请转后。

标题比较长,其实“如何用Python调用C的函数”以及“如何编写Python的C扩展”在广义上是同一件事,因为都是用C写底层实现,用Python作接口。

具体方法有很多,比如用ctypes、用SWIG等等,各种方法有利有弊。前段时间笔者用SWIG编译某小段函数一直出BUG,检查了两天才发现原来是因为MinGW 32-bit和Python 64-bit不兼容,加之后续笔者还需要用到NumPy C-API,所以现在笔者已弃坑SWIG,转用以下方法:

  • 按照Python C-API的编程规范,用C编写底层实现函数。
  • 用Python自带的disutils模块来管理编译、打包、生成Python模块。

所以后续的内容将主要围绕以上的方法来展开。

02

正文

编写C代码

假设要实现一个数学计算模块mymath,包含一个整数加法的函数add,那么首先要编写以下代码:

#include "D:\Anaconda2\include\Python.h"
/* file: mymath.c *
/// 真正实现
int add(int a, int b)
{    
return a + b; }
// 包装函数。Python调用add方法时传进来的参数在args里
PyObject* wrap_add(PyObject* self, PyObject* args)
{    
int a, b, result;    
// 解析参数     if (!PyArg_ParseTuple(args, "ii", &a, &b))        
return NULL;     result = add(a, b);    
// 返回PyObject* 类型的参数     return Py_BuildValue("i", result); }
// mymath模块所包含的函数列表
static PyMethodDef mymathMethods[] = {    
// 每行一个方法,含义依次为     // Python方法名,C方法名,参数值,方法文档     {"add", wrap_add, METH_VARARGS, "doc: add(a, b) \nreturn a + b"},
    {NULL, NULL, 0, NULL}    
// 上面的最后一行相当于结束符};// 初始化模块的方法,自动调用
// 命名要求为init后加上模块名
void initmymath()
{     PyObject* m;    
// 调用Py_InitModule方法初始化模块mymath,其中模块所具有     // 的函数列表由第二个参数提供     m = Py_InitModule("mymath", mymathMethods);
}

编译、打包与生成

在与mymath.c文件同级目录下编写setup.py文件,代码如下:

# file: setup.pyfrom distutils.core import setup, Extension  module1 = Extension('mymath',                     sources = ['mymath.c'])  setup(name = 'mymath',     version = '1.0',     description = 'This is a Math package',     ext_modules= [module1])

然后打开命令行窗口,进入到mymath.c所在目录,输入以下命令:

python setup.py build

可以看到以下输出信息:

编译、打包、生成时的输出信息.png

这个时候可以看到当前目录多了个build文件夹,一路进去可以看到mymath.pyd文件,这就是直接可调用的Python module了。继续在命令行里进入Python,可以直接调用mymath模块了。

调用效果

03

参考资料

[1] Python/C API Reference Manual, https://docs.python.org/2/c-api/

[2] 《Python基础教程》(第2版)

原文发布于微信公众号 - 人工智能LeadAI(atleadai)

原文发表时间:2018-02-12

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏北京马哥教育

grep、egrep、fgrep命令和正则表达式用法

一、简介 1.1、grep说明 grep命令简单来说就是linux系统实现文本内容筛选过滤的命令。当我们需要快速定位查找文本(通常是配置文件)中我们...

3106
来自专栏生信宝典

Linux学习 - SED操作,awk的姊妹篇

awk和sed想一对兄妹,一个出现,就会问起另一个。现在,都来了。 sed基本参数解释 sed是stream editor的简称,擅长对文件进行各种正则操作、插...

1736
来自专栏一“技”之长

iOS代码运行的磨刀石-预编译指令 原

所谓预编译,就是程序代码在编译之前,开发工具为我们预先做的一些工作。不要小瞧这些指令,没有它们,我们的代码可能寸步难行。

672
来自专栏闪电gogogo的专栏

Python——Scrapy初学

Scrapy是一个为了爬取网站数据,提取结构性数据而编写的应用框架。可以应用在包括数据挖掘,信息处理或存储历史数据等一系列的程序中。Scrapy最初是为了页面抓...

22010
来自专栏智能合约

Phalcon入门教程之Volt模板引擎

1013
来自专栏架构师小秘圈

shell脚本极简教程

一,shell题记 不懂shell的程序员不是好程序员,学习shell是为了自动化,使用自动化可以非常有效的提高工作效率。没有一个大公司不要求linux的基本技...

3446
来自专栏我有一个梦想

Python 项目实践三(Web应用程序)第二篇

接着上节的继续学习,使用Django创建网页的过程通常分三个阶段:定义URL、编写视图和编写模板。首先,你必须定义URL模式,每个URL都被映射到特定的视图——...

20710
来自专栏Linux Python 加油站

Linux学习----文本三剑客——sed(马哥教育原创)

我以前的文章介绍过grep了,今天我就来说一下第二个sed,它是stream editor的缩写。在Linux的文本文件中文本存储都是一行,显示时表现的多行其实...

1273
来自专栏非著名程序员

仿苹果数字键盘以及判断信用卡有效期的Editext

这次带来一个小小的信用卡有效期规则的Editext,额外赠送内置数字键盘的开发 首先来看下需求: 1) 月份数字: λ 数字输入0:后一位数字可输入...

1995
来自专栏互联网杂技

node中Express的use深入理解

Express的API 现在学node,不来点Express,都不好意思给人打招呼。但是,我刚接触的时候,觉得好多API,感觉乱糟糟的,没办法,大脑容量不够。不...

2804

扫描关注云+社区