美文网首页Python小哥哥
Python: C扩展初体验

Python: C扩展初体验

作者: 我爱学python | 来源:发表于2019-06-12 16:13 被阅读27次

前言

使用 Python 毋庸置疑减少了很多规则约束和开发成本,让我们能够更加专注于逻辑而非语法。但是得此失彼,开发效率提高了,却带来了运行性能的问题,所以就常常被其他门派追着暴打。

身为一个 pythoner,我们也很忧伤呀,怪我们咯..

万幸的是,虽然上帝关掉了我们一扇门,但是却为我们打开了另一扇窗,正因为底层是用 C语言 写的,所以我们可以将一些性能损耗比较大的功能,或者模块,通过 C语言 重写,然后 import xxxx 来无缝结合。

哪怕工作中比较少机会自己写C扩展, 了解这块的知识,也有利于我们更加深入了解 Python 的运行本质。

网上比较是通过 ctypes 或者 setup.py 的方式实现引用和编译安装,这边想试下最原始的方法~

快速开车

1. 实现接口函数

接口函数是什么意思?可以简单理解成就是 Python 和 C 的对接函数,举个栗子:

我们可以看到这个函数和传统意义上的 C 用法用点不同了,特别是在函数形参那边的PyObject self, PyObject args

第一个参数是 PyObject *self,这个参数是Python内部使用的,可以不用管;

第二个参数是 PyObject *args,这个参数非常重要,因为这个揽括了所有传给函数的参数。它是一个参数列表,把所有的参数都整合到

一个 string, 因此,如果我们需要解析这些参数需要用特定的姿势!我们需要用到 PyArg_ParseTuple 来解开这个扣人心弦的入口!

PyArg_ParseTuple 函数说明:

1.args就是需要转换的参数;

2.ii 就是参数类型的格式符号,这里代表 int init;(更多类型请看官网:https://docs.python.org/2/c-a...)

3.后面的 &arg1, &arg2 就是通过参数解析提取的值,存放的地方,这有点类似 C 的 scanf;

很明显,这三个参数,在数量上存在这一定的联系,也就是,传进去两个 int参数,那么就肯定是对应了两个 ii,然后就会对应存在 两个实际的"容器"内,这里要注意,一不小心就会 Segmentation fault

对应有解析参数的,肯定也有 C模块 值转换成 Python对象 的,那就是 Py_BuildValue。

Py_BuildValue 函数说明:

1.第一个参数 和 PyArg_ParseTuple 的第二个参数一样,都是格式化符号;

2.第二个参数是需要转换的参数,函数 Py_BuildValue 会把所有的返回指都组装成 tuple 给 Python

相关的官方文档:https://docs.python.org/2/c-api/arg.html

2. 定义方法列表

PyMethodDef 是一个 C结构体,用来完成一个映射,也就是便于方法查找,我们把需要被外面调用的方法都记录在这表内。

PyMethodDef 结构体成员说明:

1.第一个字段:在 Python 里面使用的方法名;

2.第二个字段:C 模块内的函数名;

3.第三个字段:方法参数类型,是无参数(METH_NOARGS) , 还是有位置参数(METH_VARARGS), 还是其他等等;

4.第四个字段:方法描述,就是通过 help() 或者 doc 可以看到的;

需要注意的是,这个列表的最后必须以 {NULL, NULL, 0, NULL} 的形式来代表声明结束,也有一些大佬用 {NULL, NULL},不过个人觉得写完整也不会累到哪去, 相反会比较直观。

正因为存在这样的一份记录表,Python 才能够寻找到相应的函数

同样的,如果我们想要找一个模块的 Python 函数 对应什么的 C模块方法,也能通过这地方比较粗暴得知,例如 Python 的 list

 3. 实现初始化函数 (关键)

需要特别注意的是,这个函数名不能像上面那样,这是有规定的,必须是 init + 模块名字,比方说,我的最后编译出来的文件是 test.so, 那我的函数名就是 inittest, 这样在 Python 导入 test 模块时,才能找到这个函数并调用。

这里调用了 Py_InitModule 函数来将模块名字和映射表结合在一起。表示 test 这个模块使用 testMethods 这个映射表。

4. 注意对象引用管理和内存泄露

Python 在对象管理、内存管理上面,有引用计数,标记-清除,分代回收等策略,其中引用计数发生的频率会非常非常高,依赖这个通常已经能够解决大部分的对象残留问题了。

所以,在我们编写 C扩展 时,也需要时刻谨记这步.

主要会用到下面两个宏:

1. 增加引用: Py_INCREF 例: Py_INCREF(pObj1)

2. 减少引用: Py_DECREF 例: Py_DECREF(pObj1)

不能直接使用 free/delete 释放,必须使用 Py_DECREF(pObj1), 然后 pObj1 = NULL 即可。

具体可以参考:

官网:https://docs.python.org/2/extending/extending.html#reference-counts

垃圾回收机制: http://www.wklken.me/posts/2015/09/29/python-source-gc.html

编译导出

gcc-I /usr/include/python2.7/ -fpic --shared -o test.so test.c

完整例子

test.c

 test.py


相关文章

  • Python: C扩展初体验

    前言: 使用 Python 毋庸置疑减少了很多规则约束和开发成本,让我们能够更加专注于逻辑而非语法。但是得此失彼,...

  • Python: C扩展初体验

    前言 使用 Python 毋庸置疑减少了很多规则约束和开发成本,让我们能够更加专注于逻辑而非语法。但是得此失彼,开...

  • C++扩展python modules

    函数详情# C语言扩展pythonPyObject 所有的python扩展类型对象 描述所有python对象再C...

  • Python 的可扩展性

    Python 具有高可扩展性,存在许多使用 C 语言或 Fortran 编写扩展的方法。必要时,Python 代码...

  • 初遇 Tensorflow

    TensorFlow 特性 ** 高度的灵活性**:向上扩展(python)、向下扩展(C++)非常方便; 真正的...

  • day2 认识python,python的基础语法和变量

    一、认识python 1、python的特性 a 可移植 b 可扩展 c 互动模式 2、python的优缺...

  • Python调用C/C++方式

    Python调用C++方式 方式一(基础篇) 这种方法叫做python的扩展 使用python这样调用 在Linu...

  • 用C++写扩展改善Python性能

    用C++写扩展改善Python性能 Tags: Boost.Python, PyBind11, md5sum, p...

  • vscode修改扩展模块的内置代码片段

    修改vscode中python扩展的代码片段 扩展模块中代码片段文件路径c:\用户\用户名\.vscode\ext...

  • python-day1初始Python

    Python优点:简单、优雅、明确;强大的模块三方库;易移植;面向对象,可扩展(c/Java) Python缺点:...

网友评论

    本文标题:Python: C扩展初体验

    本文链接:https://www.haomeiwen.com/subject/mzblfctx.html