- Preface 前言
- 第1章 引论
- 第2章 编程惯用法
- 第3章 基础语法
- 建议19:有节制地使用 from…import 语句
- 建议20:优先使用 absolute import 来导入模块
- 建议21:i+=1 不等于 ++i
- 建议22:使用 with 自动关闭资源
- 建议23:使用 else 子句简化循环(异常处理)
- 建议24:遵循异常处理的几点基本原则
- 建议25:避免 finally 中可能发生的陷阱
- 建议26:深入理解 None 正确判断对象是否为空
- 建议27:连接字符串应优先使用 join 而不是 +
- 建议28:格式化字符串时尽量使用 .format 方式而不是 %
- 建议29:区别对待可变对象和不可变对象
- 建议30:[]、() 和 {}:一致的容器初始化形式
- 建议31:记住函数传参既不是传值也不是传引用
- 建议32:警惕默认参数潜在的问题
- 建议33:慎用变长参数
- 建议34:深入理解 str() 和 repr() 的区别
- 建议35:分清 staticmethod 和 classmethod 的适用场景
- 第4章 库
- 建议36:掌握字符串的基本用法
- 建议37:按需选择 sort() 或者 sorted()
- 建议38:使用 copy 模块深拷贝对象
- 建议39:使用 Counter 进行计数统计
- 建议40:深入掌握 ConfigParser
- 建议41:使用 argparse 处理命令行参数
- 建议42:使用 pandas 处理大型 CSV 文件
- 建议43:一般情况使用 ElementTree 解析 XML
- 建议44:理解模块 pickle 优劣
- 建议45:序列化的另一个不错的选择 JSON
- 建议46:使用 traceback 获取栈信息
- 建议47:使用 logging 记录日志信息
- 建议48:使用 threading 模块编写多线程程序
- 建议49:使用 Queue 使多线程编程更安全
- 第5章 设计模式
- 第6章 内部机制
- 建议54:理解 built-in objects
- 建议55:init() 不是构造方法
- 建议56:理解名字查找机制
- 建议57:为什么需要 self 参数
- 建议58:理解 MRO 与多继承
- 建议59:理解描述符机制
- 建议60:区别 getattr() 和 getattribute() 方法
- 建议61:使用更为安全的 property
- 建议62:掌握 metaclass
- 建议63:熟悉 Python 对象协议
- 建议64:利用操作符重载实现中缀语法
- 建议65:熟悉 Python 的迭代器协议
- 建议66:熟悉 Python 的生成器
- 建议67:基于生成器的协程及 greenlet
- 建议68:理解 GIL 的局限性
- 建议69:对象的管理与垃圾回收
- 第7章 使用工具辅助项目开发
- 第8章 性能剖析与优化
建议90:使用 C/C++ 模块扩展提高性能
Python具有良好的可扩展性,利用Python提供的API,如宏、类型、函数等,可以让Python方便地进行C/C++扩展,从而获得较优的执行性能。所有这些API却包含在Python.h的头文件中,在编写C代码的时候引入该头文件即可。来看一个简单的扩展例子。
1)先用C实现相关函数:以实现素数判断为例,文件命名为testextend.c。也可以直接使用C语言实现相关函数功能后再使用Python进行包装。
include "Python.h" static PyObject *pr_isprime(PyObject *self, PyObject *args){ int n, num; if (!PyArg_ParseTuple(args, "i", &num)) # 解析参数 return NULL; if (num < 1) { return Py_BuildValue("i", 0); #C 类型的数据结构转换成Python 对象 } n = num - 1; while (n > 1){ if (num%n == 0) return Py_BuildValue("i", 0);; n--; } return Py_BuildValue("i", 1); } static PyMethodDef PrMethods[] = { {"isPrime", pr_isprime, METH_VARARGS, "check if an input number is prime or not."}, {NULL, NULL, 0, NULL} }; void initpr(void){ (void) Py_InitModule("pr", PrMethods); }
上面的代码包含以下3部分。
导出函数:C模块对外暴露的接口函数pr_isprime,带有self和args两个参数,其中参数args中包含了Python解释器要传递给C函数的所有参数,通常使用函数PyArg_ParseTuple()来获得这些参数值。
初始化函数:以便Python解释器能够对模块进行正确的初始化,初始化时要以init开头,如initp。
方法列表:提供给外部的Python程序使用的一个C模块函数名称映射表 PrMethods。它是一个PyMethodDef结构体,其中成员依次表示方法名、导出函数、参数传递方式和方法描述。看下面这个例子。
struct PyMethodDef { char* ml_name; # 方法名 PyCFunction ml_meth; # 导出函数 int ml_flags; # 参数传递方法 char* ml_doc; # 方法描述 };
参数传递方法一般设置为METH_VARARGS,如果想传入关键字参数,则可以将其与METH_KEYWORDS进行或运算。若不想接受任何参数,则可以将其设置为METH_NOARGS。该结构体必须以{NULL,NULL,0,NULL}所表示的一条空记录来结尾。
2)编写setup.py脚本。
from distutils.core import setup, Extension module = Extension('pr', sources = ['testextend.c']) setup(name = 'Pr test', version = '1.0', ext_modules = [module])
3)使用python setup.py build进行编译,系统会在当前目录下生成一个build子目录,里面包含pr.so和pr.o文件,如图8-7所示。
图8-7 使用Python进行编译
4)将生成的文件pr.so复制到Python的site_packages目录下,或者将pr.so所在目录的路径添加到sys.path中,就可以使用C扩展的模块了,如图8-8所示。
图8-8 导入编译后的模块
更多关于C模块扩展的内容请读者参考http://docs.python.org/2/c-api/index.html。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论