python 用起来十分方便,但是在执行效率上是硬伤,要是能把一些效率低的循环部分写成C,便可以极大的提升效率。在使用过程中我就遇到了这样的问题,在此做个记录。
python调用C主要有以下方法:
将C编译成DLL(WINDOWS)或者SO文件(LINUX)
在PYTHON中用接口调用,该方法使用起来十分简单
假设有add.c的中有一个叫add的函数
1.将该文件编译成SO文件:
#For Linux
$ gcc -shared -Wl,-soname,adder -o adder.so -fPIC add.c
#For Mac
$ gcc -shared -Wl,-install_name,adder.so -o adder.so -fPIC add.c
2.调用
from ctypes import *
#load the shared object file
adder = CDLL('./adder.so')
#Find sum of integers
res_int = adder.add_int(4,5)
ctypes中定义了与C对应的数据类型,详见https://docs.python.org/3.6/library/ctypes.html
该方法在初次使用时可能会觉得有点麻烦,但是一旦掌握,PYTHON调用C,将是无往不利!
该方法需要在C中写一个接口运行C代码,然后将结果传给PYTHON。编写该接口主要分为以下四步:
1.写在PYTHON中调用的函数
2.定义该函数
3.创建一个结构体
4.将结构体传给PYTHON
接口完成后只需要创建setup.py将C部分安装成PYTHON可调用的包
具体看代码:
//1.在PYTHON中执行的函数的具体内容,注意函数的命名方式
static PyObject* poptrie_pre2asn(PyObject* self, PyObject* args)
{
char *pre2asnFile;
char *ipPath;
char *asPath;
//PYTHON中读取参数并赋值给C中的变量
PyArg_ParseTuple( args, "sss", &pre2asnFile, &ipPath, &asPath );
//调用C中的函数ip2asn
int res = ip2asn(pre2asnFile,ipPath,asPath);
//返回结果到PYTHON中
return Py_BuildValue("i", res);
}
//说明文档
static char pre2asn_docs[] = "pre2ans( ): map a prefix to asn\n";
//2.声明该函数,第一个参数是在PYTHON中调用时的函数名,第二个是在C接口中的函数名
static PyMethodDef poptrie_funcs[] =
{
{"pre2asn", (PyCFunction)poptrie_pre2asn, METH_VARARGS, pre2asn_docs},
{NULL, NULL, 0, NULL}
};
//3.定义一个结构体,用于将函数具体信息传到PYTHON中,poptrie是python setup后该包的名称
static struct PyModuleDef poptriemodule = {
PyModuleDef_HEAD_INIT,
"poptrie",
"module add yourself",
-1,
poptrie_funcs
};
//4.初始化该函数
PyMODINIT_FUNC PyInit_poptrie(void)
{
return PyModule_Create(&poptriemodule);
}
参数的获取传递等具体方法请参见https://docs.python.org/3/c-api/
函数名的命名请着重注意!
SETUP.PY的编写:
from distutils.core import setup, Extension
setup(name='addList', version='1.0', \
ext_modules=[Extension('pre2asn', ['main.c'])])
有多个C文件,全写在[]中便可
安装:python setup.py install
大功告成,可以在PYTHON中调用该包了
import poptrie
res = poptrie.pre2asn(,,,)#参数请自行填写
好了,简单记录一下,就写到这了。不当之处敬请批评指正!