Python和C扩展实现方法
一、Python和C扩展
cPython是C编写的,python的扩展可以用C来写,也便于移植到C++.
编写的Python扩展,需要编译成一个.so的共享库。
Python程序中。
官方文档:https://docs.python.org/2/extending/extending.html#writing-extensions-in-c
二、举例
>>> import spam
>>> status = spam.system("ls -l")
我们需要创建一个spam.c的文件模块,这个模块是C实现。开头必须有
#include <Python.h>
下面实现以上的举子:
static PyObject * spam_system(PyObject *self, PyObject *args) { const char *comment; int sts; if (!PyArg_ParseTuple(args, "s", &command)) return NULL; sts = system(command); return Py_BuildValue("i", sts); }
上述函数的Python扩展中C函数有两个参数:self, args,这两个是必须的。
三、模块方法和函数初始化
1、定义模块及帮助文档。模块叫system,指定执行函数spam_system, 帮助文档“Execute a shell command”
static PyMethodDef SpamMethods[] = { {"system", spam_system, METH_VARARGS, "Execute a shell command."}, {NULL, NULL, 0, NULL} };
在编译完之后,导入模块,执行如下help命令,就会出现文档
In [5]: help(spam) Help on module spam: NAME spam FILE /usr/lib/python2.6/site-packages/spam.so FUNCTIONS system(...) Execute a shell command.
2、初始spam,初始化模块函数一定要init[module],保持一致
void initspam() { Py_InitModule("spam", SpamMethods); }
三、编译
1、编译模块时,需要编写setup.py文件
#!/usr/bin/env python # -*- coding: utf-8 -*- from distutils.core import setup, Extension MOD = "spam" setup(name=MOD, ext_modules=[Extension(MOD, sources=['spam.c'])])
模块名name和扩展模块。
2、进行编译
[root@local PycExt]# python setup.py build running build running build_ext building 'spam' extension gcc -pthread -fno-strict-aliasing -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i686 -mtune=atom -fasynchronous-unwind-tables -D_GNU_SOURCE -fPIC -fwrapv -DNDEBUG -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i686 -mtune=atom -fasynchronous-unwind-tables -D_GNU_SOURCE -fPIC -fwrapv -fPIC -I/usr/include/python2.6 -c spam.c -o build/temp.linux-i686-2.6/spam.o In file included from /usr/include/python2.6/pyconfig.h:4, from /usr/include/python2.6/Python.h:8, from spam.c:3: /usr/include/python2.6/pyconfig-32.h:1034:1: warning: "_POSIX_C_SOURCE" redefined In file included from /usr/include/stdio.h:28, from spam.c:1: /usr/include/features.h:162:1: warning: this is the location of the previous definition In file included from /usr/include/python2.6/pyconfig.h:4, from /usr/include/python2.6/Python.h:8, from spam.c:3: /usr/include/python2.6/pyconfig-32.h:1043:1: warning: "_XOPEN_SOURCE" redefined In file included from /usr/include/stdio.h:28, from spam.c:1: /usr/include/features.h:164:1: warning: this is the location of the previous definition gcc -pthread -shared build/temp.linux-i686-2.6/spam.o -L/usr/lib -lpython2.6 -o build/lib.linux-i686-2.6/spam.so
生成一个build的文件夹,里面有spam.so库
[root@local PycExt]# ls build setup.py spam.c
3、安装
[root@local PycExt]# python setup.py install running install running build running build_ext running install_lib copying build/lib.linux-i686-2.6/spam.so -> /usr/lib/python2.6/site-packages running install_egg_info Removing /usr/lib/python2.6/site-packages/spam-0.0.0-py2.6.egg-info Writing /usr/lib/python2.6/site-packages/spam-0.0.0-py2.6.egg-info
执行命令如上,就安装好了。
四、使用模块
In [1]: import spam In [2]: spam.system("ls -la") total 20 drwxr-xr-x. 3 root root 4096 Apr 8 22:07 . drwxr-xr-x. 10 root root 4096 Apr 8 21:01 .. drwxr-xr-x. 4 root root 4096 Apr 8 21:51 build -rw-r--r--. 1 root root 171 Apr 8 21:48 setup.py -rw-r--r--. 1 root root 549 Apr 8 22:07 spam.c Out[2]: 0 In [3]:
如上,即为python扩展相关内容...
spam.c
#include <stdio.h> #include <stdlib.h> #include "Python.h" static PyObject * spam_system(PyObject *self, PyObject *args) { const char *command; int sts; if (!PyArg_ParseTuple(args, "s", &command)) return NULL; sts = system(command); return Py_BuildValue("i", sts); } static PyMethodDef SpamMethods[] = { {"system", spam_system, METH_VARARGS, "Execute a shell command."}, {NULL, NULL, 0, NULL} }; void initspam() { Py_InitModule("spam", SpamMethods); } int main(int argc, char *argv[]) { return 0; }
setup.py
#!/usr/bin/env python # -*- coding: utf-8 -*- from distutils.core import setup, Extension MOD = "spam" setup(name=MOD, ext_modules=[Extension(MOD, sources=['spam.c'])])