Python 扩展C

来源:互联网 发布:手机淘宝自定义链接 编辑:程序博客网 时间:2024/05/16 18:28

Python 扩展C

Python 扩展C: 你写的任何代码使用任何编译语言如C,C + +或Java可以集成或导入到另一个Python脚本。此代码被认为是“扩展”.

你写的任何代码使用任何编译语言如C,C + +或Java可以集成或导入到另一个Python脚本。此代码被认为是“扩展”.

一个Python扩展模块是没有什么比一个普通的C库。Unix机器上,通常这些库(共享对象),因此结束。在Windows机器上,你通常会看到的。dll(动态链接库).

先决条件:

要开始写你的扩展,你会需要的Python头文件.

  • Unix机器上,这通常需要安装一个开发者,如特定的包 python2.5-dev.

  • Windows用户获得这些头时,他们使用的二进制Python安装包的一部分.

此外,它假设你有良好的知识的C或C+ +编写任何Python扩展使用C语言编程.

先来看看一个Python扩展:

你先看看Python扩展模块,你会被组合成四个部分的代码:

  • 头文件 Python.h.

  • 你想从你的模块的接口公开的C函数.

  • 表映射为Python开发你的函数的名称,会看到他们内部扩展模块的C函数.

  • 初始化函数.

Python.h头文件

包括在你的C源文件的的Python.h头文件,这将会给你访问内部的Python API,用于解释挂接到你的模块.

务必包括Python.h之前,您可能需要的任何其他头中。包括你需要调用Python的功能/函数.

C 函数:

你的函数的C语言实现的签名将始终采取以下三种形式之一:

static PyObject *MyFunction( PyObject *self, PyObject *args );static PyObject *MyFunctionWithKeywords(PyObject *self,                                 PyObject *args,                                 PyObject *kw);static PyObject *MyFunctionWithNoArgs( PyObject *self );

上述声明中的每一个返回一个Python对象。作为在C,如果你不想你的函数返回一个值void函数在Python中有没有这样的事情,返回Ç相当于Python的没有值的。 Python的头,我们定义一个宏,Py_RETURN_NONE.

您的C函数的名称可以是任何你喜欢的,因为他们将永远不会被外界的扩展模块。因此,他们将被定义为静态函数.

你的C函数通常被命名为共同结合的Python模块和函数名,如下所示:

static PyObject *module_func(PyObject *self, PyObject *args) {   /* Do your stuff here. */   Py_RETURN_NONE;}

这将是一个Python函数调用功能模块的模块内。你可以把这个方法表指针的C函数的模块,通常接下来在你的源代码.

该方法的映射表:

这个方法表是一个简单的数组PyMethodDef结构。这种结构看起来像这样:

struct PyMethodDef {   char *ml_name;   PyCFunction ml_meth;   int ml_flags;   char *ml_doc;};

下面是这个结构的成员描述:

  • ml_name: 这是Python解释会呈现在Python程序中使用时,它的函数的名称.

  • ml_meth: 这必须是一个函数的地址有任何描述以前seection的签名之一.

  • ml_flags: 这告诉解释器使用的三个签名ml_meth.

    • 此标志通常有一个值METH_VARARGS.

    • 这个标志可以按位或操作与METH_KEYWORDS如果你想允许进入你的函数的关键字参数.

    • 这也有值,指出你不想接受任何参数的METH_NOARGS.

  • ml_doc: 这是该函数的文档字符串,这可能是空的,如果你不喜欢写一个。

此表需要适当的成员终止与定点NULL的组成和0值.

例子:

对于上述定义的函数,我们将有以下方法映射表:

static PyMethodDef module_methods[] = {   { "func", (PyCFunction)module_func, METH_NOARGS, NULL },   { NULL, NULL, 0, NULL }};

初始化函数:

扩展模块的最后部分是初始化函数。这个函数被调用的模块被加载时由Python解释。它需要的功能被命名为initModule,其中module是模块的名称.

初始化函数需要从库中,您将建立导出。 Python的头定义PyMODINIT_FUNC包括要做到这一点我们正在编译的特定环境中适当的。所有您需要做的是使用它时定义函数.

你的C初始化函数一般有以下的整体结构:

PyMODINIT_FUNC initModule() {   Py_InitModule3(func, module_methods, "docstring...");}

这里是Py_InitModule3功能描述:

  • func: 这是要导出的函数.

  • module_methods: 这是上面定义的映射表名称.

  • docstring: 这是你想给您的扩展注释.

把这个一起,看起来像下面:

#include static PyObject *module_func(PyObject *self, PyObject *args) {   /* Do your stuff here. */   Py_RETURN_NONE;}static PyMethodDef module_methods[] = {   { "func", (PyCFunction)module_func, METH_NOARGS, NULL },   { NULL, NULL, 0, NULL }};PyMODINIT_FUNC initModule() {   Py_InitModule3(func, module_methods, "docstring...");}

例子:

一个简单的例子,使所有上述概念的使用:

#include static PyObject* helloworld(PyObject* self){    return Py_BuildValue("s", "Hello, Python extensions!!");}static char helloworld_docs[] =    "helloworld( ): Any message you want to put here!!\n";static PyMethodDef helloworld_funcs[] = {    {"helloworld", (PyCFunction)helloworld,      METH_NOARGS, helloworld_docs},    {NULL}};void inithelloworld(void){    Py_InitModule3("helloworld", helloworld_funcs,                   "Extension module example!");}

这里Py_BuildValue功能是用来建立一个Python值。除以上hello.c文件中的代码。我们会看到如何编译和安装此模块从Python脚本调用.

构建和安装扩展:

distutils包分布在一个标准的Python模块,纯Python扩展模块,使得它很容易。模块源代码的形式分布在建成并通过通常被称为如下setup.py安装脚本安装.

对于上述模块,你就必须准备以下setup.py脚本:

from distutils.core import setup, Extensionsetup(name='helloworld', version='1.0',  \      ext_modules=[Extension('helloworld', ['hello.c'])])

现在使用下面的命令,将执行所有必需的编译和链接步骤,正确的编译器和链接器的命令和标志,并复制到适当的目录中生成的动态库:

$ python setup.py install

在基于Unix的系统,你最有可能需要以root身份运行此命令才能有权限写的site-packages目录。这通常是不能在Windows中存在的问题.

导入扩展:

一旦你安装您的扩展,你就可以在你的Python脚本如下,扩展导入和调用:

#!/usr/bin/pythonimport helloworldprint helloworld.helloworld()

这将产生以下结果:

Hello, Python extensions!!

传递函数参数:

因为你最有可能要定义函数接受参数,您可以使用您的C函数的其他签名之一。

举例来说,下面的函数,接受一些参数,将这样定义:

static PyObject *module_func(PyObject *self, PyObject *args) {   /* Parse args and do something interesting here. */   Py_RETURN_NONE;}

看起来像这样的方法表,其中包含新功能的一个条目:

static PyMethodDef module_methods[] = {   { "func", (PyCFunction)module_func, METH_NOARGS, NULL },   { "func", module_func, METH_VARARGS, NULL },   { NULL, NULL, 0, NULL }};

你可以使用API PyArg_ParseTuple函数来提取从一个PyObject的传递到你的C函数的指针参数.

PyArg_ParseTuple的第一个参数args参数。这是你会被解析的对象。第二个参数是一个格式字符串,描述你希望他们出现的论点。每个参数代表在如下的格式字符串由一个或多个字符.

static PyObject *module_func(PyObject *self, PyObject *args) {   int i;   double d;   char *s;   if (!PyArg_ParseTuple(args, "ids", &i, &d, &s)) {      return NULL;   }      /* Do something interesting here. */   Py_RETURN_NONE;}

编译你的模块的新版本和导入它将使你与任意数量的任何类型的参数调用新功能:

module.func(1, s="three", d=2.0)module.func(i=1, d=2.0, s="three")module.func(s="three", d=2.0, i=1)

你也许可以想出更多的变化.

PyArg_ParseTuple 函数:

这里是PyArg_ParseTuple功能的标准签名:

int PyArg_ParseTuple(PyObject* tuple,char* format,...)

这个函数返回错误0,和值不等于成功为0。元组的PyObject *这是C函数的第二个参数。这里的格式是一个C字符串描述强制性和可选参数.

这里是一个格式代码PyArg_ParseTuple功能列表:

CodeC typeMeaningccharA Python string of length 1 becomes a C char.ddoubleA Python float becomes a C double.ffloatA Python float becomes a C float.iintA Python int becomes a C int.llongA Python int becomes a C long.Llong longA Python int becomes a C long longOPyObject*Gets non-NULL borrowed reference to Python argument.schar*Python string without embedded nulls to C char*.s#char*+intAny Python string to C address and length.t#char*+intRead-only single-segment buffer to C address and length.uPy_UNICODE*Python Unicode without embedded nulls to C.u#Py_UNICODE*+intAny Python Unicode C address and length.w#char*+intRead/write single-segment buffer to C address and length.zchar*Like s, also accepts None (sets C char* to NULL).z#char*+intLike s#, also accepts None (sets C char* to NULL).(...)as per ...A Python sequence is treated as one argument per item.| The following arguments are optional.: Format end, followed by function name for error messages.; Format end, followed by entire error message text.

返回值:

Py_BuildValue需要PyArg_ParseTuple确实很像一个格式字符串。你传递这些值构建的地址,代替通过实际值。

下面是一个例子显示了如何实现一个附加功能:

static PyObject *foo_add(PyObject *self, PyObject *args) {   int a;   int b;   if (!PyArg_ParseTuple(args, "ii", &a, &b)) {      return NULL;   }   return Py_BuildValue("i", a + b);}

这是什么,它看起来像如果在Python实现:

def add(a, b):   return (a + b)

你可以从你的函数返回如下两个值,这将被捕捉在Python中使用列表.

static PyObject *foo_add_subtract(PyObject *self, PyObject *args) {   int a;   int b;   if (!PyArg_ParseTuple(args, "ii", &a, &b)) {      return NULL;   }   return Py_BuildValue("ii", a + b, a - b);}

这是什么,它看起来像如果在Python实现:

def add_subtract(a, b):   return (a + b, a - b)

Py_BuildValue 函数:

这里标准签名就是Py_BuildValue函数:

PyObject* Py_BuildValue(char* format,...)

这里的格式是描述的Python对象,建立一个C字符串。 Py_BuildValue以下参数是C结果的值。的PyObject*结果是一个新的参考.

下表列出了常用的代码串,其中零个或更多的加入到字符串格式.

CodeC typeMeaningccharA C char becomes a Python string of length 1.ddoubleA C double becomes a Python float.ffloatA C float becomes a Python float.iintA C int becomes a Python int.llongA C long becomes a Python int.NPyObject*Passes a Python object and steals a reference.OPyObject*Passes a Python object and INCREFs it as normal.O&convert+void*Arbitrary conversionschar*C 0-terminated char* to Python string, or NULL to None.s#char*+intC char* and length to Python string, or NULL to None.uPy_UNICODE*C-wide, null-terminated string to Python Unicode, or NULL to None.u#Py_UNICODE*+intC-wide string and length to Python Unicode, or NULL to None.w#char*+intRead/write single-segment buffer to C address and length.zchar*Like s, also accepts None (sets C char* to NULL).z#char*+intLike s#, also accepts None (sets C char* to NULL).(...)as per ...Builds Python tuple from C values.[...]as per ...Builds Python list from C values.{...}as per ...Builds Python dictionary from C values, alternating keys and values.

Code {...} builds dictionaries from an even number of C values, alternately keys and values. For example, Py_BuildValue("{issi}",23,"zig","zag",42) returns a dictionary like Python's {23:'zig','zag':42}

0 0
原创粉丝点击