Python学习入门手册以及CFFI

原文地址:http://www.codedata.com.tw/python/python-tutorial-the-1st-class-1-preface/

重点在于文中嵌入的PPT文件,具体内容参加上述链接地址。

目的,http://www.zhihu.com/question/22718672 Windows 用户如何运行一个 GitHub 上的 Python 脚本?

python被称为是“胶水语言”,号称能够“方便地”调用其他语言,比如c。但是实际操作中,对于非码农出身的人来说写语言接口还是很痛苦的事情。(我就从来没有试图去写过ctype或者swig之类的高级货,一眼看去完全被吓到。)最近发现了一个python模块,“C Foreign Function Interface for Python”(cffi),它把很多低层次的接口都隐藏起来,用户从而不需要写那些让人抓狂的接口文件也能非常方便的调用C语言了。(另外一种方便调用C语言的办法是使用Cython],我有时间会在另一篇文章介绍。)

假设我有一个写好的C语言函数,定义在foo.c文件中,这个函数调用了GSL(GNU Scientific Library)里面的Bessel函数。

// foo.c
#include <gsl/gsl_sf_bessel.h>

double foo(double a, double b){
    return gsl_sf_bessel_J0(a + b);
}

接下来,我们想在python中用cffi模块调用这个用C语言定义的函数foo。首先,我们要通过cffi告诉python这个函数foo的“签名”,即输入和输出的数据类型。

# demo_1.py
from cffi import FFI
ffi = FFI()
ffi.cdef("double foo(double, double);")

下一步,我们要把函数foo在C语言中的定义告诉python。这里有两种方式可以实现: 1. 把foo.c这个源文件直接传递python 2. 把foo.c编译成shared library,然后再传递给python 我们先看第一种方式:

# demo_1.py (cont.)
import os
file_dir = os.path.abspath('.')
lib = ffi.verify("#include <foo.c>", include_dirs=[file_dir], libraries=['gsl', 'gslcblas'])

verify这个method就是用来传递函数foo的定义的。它的用法是,用一个string直接告诉python,我要载入foo.c这个包含函数foo定义的C语言源文件。参数include_dirs说明foo.c所在的位置。因为我把demo_1.py文件和foo.c放在了同一个文件家里,所以我可以用os.path.abspath('.')来提取foo.c的文件夹地址。最后,参数libraries是需要用到其他的库文件,gsl库文件和gslclbas文件,因为函数foo调用了GSL库里面的Bessel函数。 这样就搞定了,我们可以在python中直接调用C语言定义的函数foo了:

# demo_1.py (cont.)
a, b = 1.2, 3.4
print lib.foo(a, b)

之前说到第二种传递函数foo的定义的方式是通过shared library,这么做的好处是把foo和其他用到的库文件比如GSL“打包”成一个新的库文件,比如叫libfoo.so,之后就可以在python中直接使用libfoo.so而无需再指定其他库文件了。具体方法如下:

gcc foo.c -shared -lgsl -lgslcblas -o libfoo.so

注意在这一步中我们把gsl和gslclbas这两个库文件“打包”进了libfoo.so,然后我们就可以在python中通过cffi来调用libfoo.so了。

# demo_2.py
from cffi import FFI
ffi = FFI()
ffi.cdef("double foo(double, double);")

import os
file_dir = os.path.abspath('.')
lib = ffi.verify("#include <foo.c>", include_dirs=[dir], library_dirs=[dir], libraries=['foo'])

a, b = 1.2, 3.4
print lib.foo(a, b)

注意观察verify中的两点使用变化: 1. 多了一个参数library_dirs用来说明库文件foo的位置,这是因为libfoo.so经常不在系统默认的PATH上(而gsl等库文件确实一般安装在PATH上,而且我们也需要用libraray_dirs这个参数来指明)。 2. 参数libraries的值变成了[foo],而不是['gsl', 'gslcblas']。这是因为我们已经把gslgslcblas里的必要信息打包进了libfoo.so里面。

最后,假如函数foo的定义非常复杂,我们不想把它直接传给python,那么就可以定义一个头文件foo.h来包含foo的函数声名,

// foo.h
#ifndef foo_h__
#define foo_h__
double foo(double, double);
#endif

然后把该头文件传递过去就可以了,即

ffi.verify("#include <foo.h>", include_dirs=[dir], library_dirs=[dir], libraries=['foo'])
配置CFFI接口,参考https://cffi.readthedocs.org/en/latest/installation.html
已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页