原创 使用 C 或 C++ 扩展 Python

发布时间:2021-06-24 22:09:12 浏览 88 来源:猿笔记 作者:鱼儿塘

    添加新的Python内置模块会很简单。实现新的内置对象类型;调用C的库函数和系统调用。PythonAPI(应用程序编程接口)定义了一系列函数、宏和变量,可以访问Python运行时系统的大部分内容。Python的API可以通过在一个C源文件中引用`"Python.h"`头文件来使用。扩展模块的编写方式取决与你的目的以及系统设置;扩展模块无法在其他Python实现上工作。如果你的用例调用了C库或系统调用,我们把功能强大的函数放入C文件great\\_module.c中,它负责告诉Python这个模块里有哪些函数可以被Python调用。


    如果能使用C,很容易添加新的Python内置模块。下面两件用Python不能直接做到的事情,可以通过extensionmodules来实现:实现新的内置对象类型;调用c的库函数和系统调用。

    为了支持扩展,PythonAPI(应用编程接口)定义了一系列函数、宏和变量,可以访问Python运行时系统的大部分内容。Python API可以通过引用C源文件中的` Python.h ' `头文件来使用。

    扩展模块的编写方法取决于你的用途和系统设置。这将在以下章节中详细描述。

    注意:C扩展接口特指CPPython,扩展模块不能在其他Python实现上工作。在大多数情况下,应该避免编写C扩展来保持可移植性。例如,如果您的用例调用C库或系统调用,您应该考虑使用`ctypes`](

    一个简单的例子

    ------

    例如,我们有这样一个c函数:

    intgreat_function(inta){

    returna+1;

    }

    期望在Python里这样使用:

    >>fromgreat_moduleimportgreat_function

    >>great_function(2)

    考虑最简单的情况。我们在c文件great \ \ _ module.c中加入了强大的函数。

    #include

    intgreat_function(inta){

    returna+1;

    }

    staticPyObject*_great_function(PyObject*self,PyObject*args)

    {

    int_a;

    intres;

    if(!PyArg_ParseTuple(args,"i",&_a))

    returnNULL;

    res=great_function(_a);

    returnPyLong_FromLong(res);

    }

    staticPyMethodDefGreateModuleMethods[]={

    {

    "great_function",

    _great_function,

    METH_VARARGS,

    ""

    },

    {NULL,NULL,0,NULL}

    };

    PyMODINIT_FUNCinitgreat_module(void){

    (void)Py_InitModule("great_module",GreateModuleMethods);

    }

    除了函数great\\_function外,这个文件中还有以下部分:

    *包裹函数\\_great\\_function。它负责将Python的参数转化为C的参数(PyArg\\_ParseTuple),调用实际的great\\_function,并处理great\\_function的返回值,最终返回给Python环境。

    *导出表格大模块方法。它负责告诉Python这个模块中哪些函数可以被Python调用。导出表可以随意命名,每一项有四个参数:第一个参数是提供给Python环境的函数名,第二个参数是\\_great\\_function,即包装函数。第三个参数的含义是参数变长,第四个参数是描述性字符串。导出表始终以{空,空,0,空}结尾。

    *导出函数initgreat\\_module。它的名称不是可选的,但是您的模块名称以init作为前缀。模块名称与导出功能中的导出表相关联。

    2.头文件

    -

    我们在代码中导入了这样一个头文件

    #include

    这将导入PythonAPI(如果您愿意,您可以在此添加描述模块目标和版权信息的注释)。

    注意:Python可能会定义一些会影响某些系统上标准头文件的预处理器定义,所以在包含任何标准头文件之前,必须包含Python . h’。建议总是在Python.h之前定义` py _ ssize _ t _ clean '。勾选【提取扩展函数参数】(

    除了那些已经定义在头文件中的之外,所有用户可见的符号都定义在`Python.h`中,并拥有前缀`Py`或`PY`。为了方便,以及为了让Python解释器应用广泛,`"Python.h"`也包含了少量标准头文件:``,``,``,和``。如果后面的头文件在你的系统上不存在,还会直接声明函数`malloc()`,`free()`和`realloc()`。

    3.编译和使用

    ---

    在Windows下面,在VisualStudio命令提示符下编译这个文件的命令是

    cl/LDgreat_module.c/ogreat_module.pyd-IC:\\Python27\\includeC:\\Python27\\libs\\python27.lib

    /LD即生成动态链接库。编译成功后在当前目录可以得到great\\_module.pyd(实际上是dll)。这个pyd可以在Python环境下直接当作module使用。

    1.4在Linux下面,则用gcc编译:

    gcc-fPIC-sharedgreat_module.c-ogreat_module.so-I/usr/include/python2.7/-lpython2.7

    在当前目录下得到great\\_module.so,同理可以在Python中直接使用。

    4.包装功能

    ---

    下面看下包裹函数\\_great\\_function:

    staticPyObject*_great_function(PyObject*self,PyObject*args)

    {

    int_a;

    intres;

    if(!PyArg_ParseTuple(args,"i",&_a))

    returnNULL;

    res=great_function(_a);

    returnPyLong_FromLong(res);

    }

    有一种方法可以直接把python参数表转换成c函数。c函数总是有两个参数,通常命名为self和args。

    对于模块级函数,自身参数指向模块对象;对于对象实例,它指向方法。

    args参数是指向一个Python的tuple对象的指针,其中包含参数。每个tuple项对应一个调用参数。这些参数也全都是Python对象---要在我们的C函数中使用它们就需要先将其转换为C值。PythonAPI中的函数[`PyArg_ParseTuple()`](

    [`PyArg_ParseTuple()`](

    再看看下面的代码:

    if(!PyArg_ParseTuple(args,"s",&command))

    returnNULL;

    如果在参数列表中检测到错误,将根据`PyArg_ParseTuple()`](

    下一个语句使用函数`great_function()`,传递给他的参数是刚才从[`PyArg_ParseTuple()`](

    res=great_function(_a);

    我们的`res=great_function()`函数必须返回`res`的值作为Python对象。这通过使用函数[`PyLong_FromLong()`](

    returnPyLong_FromLong(res);

    在这种情况下,返回一个整数对象(该对象在Python堆中管理)。

    如果你的C函数没有有用的返回值(一个返回void的函数),你必须返回None。(您可以使用` py _ retire _ none `宏来完成它):

    Py_INCREF(Py_None);

    returnPy_None;

    [`Py_None`](

    5.模块方法表

    -----

    为了展示`great_function()`如何被Python程序调用。把函数声明为可以被Python调用,需要先定义一个方法表"methodtable"。

    staticPyMethodDefGreateModuleMethods[]={

    {

    "great_function",

    _great_function,

    METH_VARARGS,

    ""

    },

    {NULL,NULL,0,NULL}

    };

    注意第三个参数(`METH_VARARGS`),这个标志指定会使用C的调用惯例。可选值有`METH_VARARGS`、`METH_VARARGS|METH_KEYWORDS`。值`0`代表使用[`PyArg_ParseTuple()`](

    如果单独使用`METH_VARARGS`,函数会等待Python传来tuple格式的参数,并最终使用[`PyArg_ParseTuple()`](

    `METH_KEYWORDS`值表示接受关键字参数。这种情况下C函数需要接受第三个`PyObject*`对象,表示字典参数,使用[`PyArg_ParseTupleAndKeywords()`](

    6.初始化函数

    ----

    PyMODINIT_FUNCinitgreat_module(void){

    (void)Py_InitModule("great_module",GreateModuleMethods);

    }

作者信息

鱼儿塘 [等级:3] 全栈工程师
发布了 37 篇专栏 · 获得点赞 7 · 获得阅读 3443

相关推荐 更多