混合编程:用 C 语言来扩展 Python 大法吧!

作者: 链球选手 | 来源:发表于2016-04-11 22:16 被阅读3709次

    Python 实在是一种让人上瘾的编程语言,简洁的语法+丰富的扩展包,几乎可以用 Python 做任何事情,唯一的黑点似乎就是「慢」,但是与高效的编译语言 C\C++ 互联以后,可以解决脚本语言运行速度慢的问题,甚至用来做一些计算密集型的工作,比如 CFD。
    这一篇介绍纯 C 语言扩展 Python。

    为什么是swig?

    Python底层就是 C\C++,有原生的 C\C++ 接口,用来传递变量,但是完全手写中间层对于我这样的业余 Coder 实在太痛苦了,这不是一件很有意思的工作。事实上,即使在Python的官方文档里也推荐用第三方的接口工具处理。

    Third party tools like Cython, cffi, SWIG and Numba offer both simpler and more sophisticated approaches to creating C and C++ extensions for Python.

    除了以上的第三方工具外,还有 sip,Boost.python,pyrex等好用的工具,在这篇 文章 里初步介绍了 C\C++ 扩展Python的各种方法。
    之前用过Boost.python,可能是我之前没接触过Boost吧,不是很喜欢,感觉不够轻量级,然后对swig一见倾心的原因是其对于纯 C 的良好支持(当时写这篇文章的时候对 C++ 莫名的反感,虽然现在已经入了 C++ 的坑了)。

    怎么安装swig?

    1.Mac OS
    强烈建议用brew来装

    brew install swig
    

    一条命令搞定,妈妈再也不用担心你的依赖问题了。

    2.Windows
    博主暂时脱离windows开发环境一会儿,建议参考官方文档

    3.Linux
    大名鼎鼎的apt-get install

    怎么使用swig?

    我参考了官方文档里的一个示例程序,最终的目的是生成一个动态链接库和一个供调用的py文件。

    • 声明函数先
      创建一个example.h头文件来声明这个函数:
    /*File: example.h*/
    int fact(int n);
    
    • 定义函数
      创建一个example.c的文件(用来计算 n!):
    /* File: example.c */
    #include "example.h"
    int fact(int n) {
        if (n < 0){
       /* This should probably return an error, but this is simpler */
            return 0; }
        else  if (n == 0) {
                return 1;
                        }
        else {
                /* testing for overflow would be a good idea here */
                return n * fact(n-1);
              }
     }
    
    • 关键一步
      我们还需要创建一个example.i文件来配置swig
    /* File: example.i */
    %module example
    
    %{
    #define SWIG_FILE_WITH_INIT
    #include "example.h"
    %}
    
    int fact(int n);
    

    简单解释一下这个配置文件,#define SWIG_FILE_WITH_INIT宏规定这个 C 文件将会被编译成 Python 模块,#include "example.h" 给出需要包含的头文件,最后一句在example.i声明了这个函数,就是这么简单嘛。
    有了这三个文件之后,我们需要先编译出一个 Python 文件,在终端运行:

    swig -python example.i
    

    如果编译的是C++文件,需要加上-C++选项:

    swig -c++ -python example.i
    

    运行完这个命令后,在工作目录里会出现example_wrap.cexample.cxx以及一个example.py的Python文件,但是现在这个模块还不能直接调用,因为还缺少动态链接库,如果强行调用会出现这种错误:

    ImportError: No module named '_example'
    

    接下来需要编译出一个shared object file,在Linux平台里是so文件,在windows下是Dll文件,有两种方法完成这个步骤,官方文档中推荐使用distutils,即Python的setup.py生成模块:

    """
        setup.py file for SWIG example
    """
    from distutils.core import setup, Extension
    
    example_module = Extension('_example',
                                   sources=['example_wrap.c', 'example.c'],
                                   )
    setup(name = 'example',
        version = '0.1',
        author = "SWIG Docs",
        description = """Simple swig example from docs""",
        ext_modules = [example_module],
        py_modules = ["example"],
        )
    

    然后在终端里输入:

    python setup.py build_ext --inplace
    

    build_ext告诉Python需要编译的是扩展模块,--inplace会确保编译生成的文件放在当前目录中。
    运行完这个命令后,会在工作目录出现一个so文件,这时example.py文件可以直接被Python调用:

    10! = 362880

    来自 Cescfangs 的博客:fangs.in

    相关文章

      网友评论

        本文标题:混合编程:用 C 语言来扩展 Python 大法吧!

        本文链接:https://www.haomeiwen.com/subject/ogvilttx.html