虽然Python简洁方便、深得人心,但用Python去实现(pip install无法解决时)某种处理大数据的算法,往往令人头疼。Python实现的代码往往是低效的,这时候需要C/C++来拯救。
本文介绍一种在Python中使用C/C++的方法。
首先,您需要Cython。
我们会把C/C++实现的算法打包成Python的扩展模块供Python代码调用。
创建目录algo
下面有4个文件
- algo_c.cpp,C/C++的实现在此
- algo_c.h,C/C++的头文件,声明函数接口
- algo.pyx,Cython代码,把C/C++函数接口包裹成Python函数接口
- setup.py,配置及编译选项
我们再倒过来逐一介绍
#setup.py
from distutils.core import setup, Extension
from Cython.Build import cythonize
import numpy as np
extensions = [
Extension('algo', ['algo.pyx', 'algo_c.cpp'],
include_dirs = [np.get_include()],
language='c++',
include_dirs = [np.get_include(), 'some_path_to_include'],
library_dirs=['some_path_to_library'],
libraries=['some_name'],
extra_compile_args=["-std=c++11"],
extra_link_args=["-std=c++11"]),
]
#依次是 扩展模块的名称、 源文件(.pyx, .cpp)、 依赖的头文件地址(使用numpy则需添加np.get_include())、 语言(默认是C)、依赖的库(.so)地址、 依赖的库名称(e.g., for "libname.so", here is "name" not "lname")、 使用C++11标准、 使用C++11标准
setup(
ext_modules = cythonize(extensions)
)
#algo.pyx
import numpy as np
cimport numpy as np
np.import_array()
#引入需要的C/C++函数接口 (在algo_c.h中)
cdef extern from "algo_c.h":
void some_function(float* arg0, int arg1, int arg2);
cimport cython
@cython.boundscheck(False) # turn off bounds-checking for entire function
@cython.wraparound(False) # turn off negative index wrapping for entire function
@cython.nonecheck(False)
#将引入的C/C++接口包裹成Python接口, 注意对numpy.ndarray的处理
def some_function_func(np.ndarray[float, ndim=2, mode="c"] in_array0 not None):
some_function(<float*> np.PyArray_DATA(in_array0), in_array0.shape[0], in_array0.shape[1])
//algo_c.h
void some_function(float* arg0, int arg1, int arg2);
//algo_c.cpp
void some_function(float* arg0, int arg1, int arg2){
//... 函数的具体实现在此
return;
}
在unix环境下通过
python setup.py build_ext --inplace
生成可用的扩展模块,使用时
#test.py
import numpy as np
from algo import some_function_func
x = np.zeros([3,3],dtype=np.float32)
some_function_func(x)
Reference