在Python中使用C/C++

虽然Python简洁方便、深得人心,但用Python去实现(pip install无法解决时)某种处理大数据的算法,往往令人头疼。Python实现的代码往往是低效的,这时候需要C/C++来拯救。

本文介绍一种在Python中使用C/C++的方法。

首先,您需要Cython

我们会把C/C++实现的算法打包成Python的扩展模块供Python代码调用。

创建目录algo

下面有4个文件

我们再倒过来逐一介绍

 
21
1
#setup.py
2
from distutils.core import setup, Extension
3
from Cython.Build import cythonize
4
5
import numpy as np
6
7
extensions = [
8
    Extension('algo', ['algo.pyx', 'algo_c.cpp'], 
9
              include_dirs = [np.get_include()],
10
              language='c++',
11
              include_dirs = [np.get_include(), 'some_path_to_include'],
12
              library_dirs=['some_path_to_library'], 
13
              libraries=['some_name'],
14
              extra_compile_args=["-std=c++11"],  
15
              extra_link_args=["-std=c++11"]),
16
]
17
#依次是 扩展模块的名称、 源文件(.pyx, .cpp)、 依赖的头文件地址(使用numpy则需添加np.get_include())、 语言(默认是C)、依赖的库(.so)地址、 依赖的库名称(e.g., for "libname.so", here is "name" not "lname")、 使用C++11标准、 使用C++11标准
18
19
setup(
20
    ext_modules = cythonize(extensions)
21
)

 
19
1
#algo.pyx
2
from __future__ import division
3
import numpy as np
4
cimport numpy as np
5
6
np.import_array()
7
8
#引入需要的C/C++函数接口 (在algo_c.h中)
9
cdef extern from "algo_c.h":
10
    void some_function(float* arg0, int arg1, int arg2);
11
12
cimport cython
13
@cython.boundscheck(False) # turn off bounds-checking for entire function
14
@cython.wraparound(False)  # turn off negative index wrapping for entire function
15
@cython.nonecheck(False)
16
17
#将引入的C/C++接口包裹成Python接口, 注意对numpy.ndarray的处理
18
def some_function_func(np.ndarray[float, ndim=2, mode="c"] in_array0 not None):
19
    some_function(<float*> np.PyArray_DATA(in_array0), in_array0.shape[0], in_array0.shape[1])

 
2
1
//algo_c.h
2
void some_function(float* arg0, int arg1, int arg2);

 
5
1
//algo_c.cpp
2
void some_function(float* arg0, int arg1, int arg2){
3
  //... 函数的具体实现在此
4
  return;
5
}

在unix环境下通过

 
1
1
python setup.py build_ext --inplace

生成可用的扩展模块,使用时

 
5
1
#test.py
2
import numpy as np
3
from algo import some_function_func
4
x = np.zeros([3,3],dtype=np.float32)
5
some_function_func(x)

Reference

Python中使用C代码

Working with Numpy