Python语言最初是用C语言实现的一种脚本语言,后来被称为CPython,是由于后来又有其它语言实现的Python,好比Python实现的Python——PyPy,Java语言实现的Python——Jython,.Net实现的Python——IronPython。linux
CPython具备优良的开放性和可扩展性,并提供了方便灵活的应用程序接口(API),从而使得C/C++程序员可以在各个级别上对Python解释器的功能进行扩展。程序员
Python的C语言接口很适合封装C语言实现的各类函数,若是要封装C++的类,使用boost_python或者SWIG更方便和合适。python爬虫
假设咱们有一个C函数:python2.7
/* 文件名: mylib.c */ int addone(int a) { return a+1; }
若是想在Python解释器中调用该函数,则应该首先将其实现为Python中的一个模块,这须要编写相应的封装接口,以下所示:函数
/* wrap_mylib.c */ #include <Python.h> #include "mylib.h" PyObject* wrap_addone(PyObject* self, PyObject* args) { int n, result; if (! PyArg_ParseTuple(args, "i:fact", &n)) return NULL; result = addone(n); /*这里调用C函数 */ return Py_BuildValue("i", result); } static PyMethodDef mylibMethods[] = { {"addone", wrap_addone, METH_VARARGS, "Add one to N"}, {NULL, NULL} }; void initmylib() { PyObject* m; m = Py_InitModule("mylib", mylibMethods); }
上面就是一个典型的Python扩展模块,它至少应该包含三个部分:ui
要在Python解释器中调用C语言中的某个函数,首先要为它编写对应的导出函数,上述例子中的导出函数为wrap_addone。在Python的C语言扩展中,全部的导出函数都具备相同的函数原型:spa
PyObject* wrap_method(PyObject* self, PyObject* args);
这个函数是Python解释器和C函数进行交互的接口,通常以wrap_开头后面跟上C语言的函数名,这样命名把导出函数和C语言函数对应起来使得代码更加清晰。它带有两个参数:self和args。指针
参数self 只在C函数被实现为内联方法(built-in method)时才被用到,一般该参数的值为空(NULL)。
参数args 中包含了Python解释器要传递给C函数的全部参数,一般使用Python的C语言扩展接口提供的函数PyArg_ParseTuple()来得到这些参数值。code
全部的导出函数都返回一个PyObject指针,若是对应的C函数没有真正的返回值(即返回值类型为void),则应返回一个全局的None对象(Py_None),并将其引用计数增1,以下所示:
PyObject* wrap_method(PyObject *self, PyObject *args) { Py_INCREF(Py_None); return Py_None; }
方法列表中列出了全部能够被Python解释器使用的方法,上述例子对应的方法列表为:
static PyMethodDef mylibMethods[] = { {"addone", wrap_addone, METH_VARARGS, "Add one to N"}, {NULL, NULL} };
方法列表中的每项由四个部分组成:
方法名是从Python解释器中调用该方法时所使用的名字。
参数传递方式则规定了Python向C函数传递参数的具体形式,可选的两种方式是METH_VARARGS和METH_KEYWORDS,其中METH_VARARGS是参数传递的标准形式,它经过Python的元组在Python解释器和C函数之间传递参数,若采用METH_KEYWORD方式,则Python解释器和C函数之间将经过Python的字典类型在二者之间进行参数传递。
全部的Python扩展模块都必需要有一个初始化函数,以便Python解释器可以对模块进行正确的初始化。Python解释器规定全部的初始化函数的函数名都必须以init开头,并加上模块的名字。对于模块mylib来讲,则相应的初始化函数为:
void initmylib() { PyObject* m; m = Py_InitModule("mylib", mylibMethods); }
当Python解释器须要导入该模块时,将根据该模块的名称查找相应的初始化函数,一旦找到则调用该函数进行相应的初始化工做,初始化函数则经过调用Python的C语言扩展接口所提供的函数Py_InitModule(),来向Python解释器注册该模块中全部能够用到的方法。
要在Python解释器中使用C语言编写的扩展模块,必须将其编译成动态连接库的形式。下面以Linux为例,介绍如何将C编写的Python扩展模块编译成动态连接库:
$ gcc -fpic -shared -o mylib.so \ -I/usr/include/python2.7 \ mylib.c wrap_mylib.c
上面编译生成的Python扩展模块的动态连接库,能够在Python中直接import。以下所示:
veelion@gtx:~$ python Python 2.7.12 (default, Nov 19 2016, 06:48:10) [GCC 5.4.0 20160609] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> import example >>> example.addone(7) 8 >>>
这里生成的.so动态库和上一篇中不用Python的C语言生成的动态库是不同的,从生成过程和使用方法就能够看出来,这里的动态库使用起来感受就是一个Python模块,直接import就能够了。