Python 高手编程系列四百六十:使用 C 或者 C++编写扩展

当我们谈论使用不同语言的扩展时,我们几乎主要考虑 C 和 C++。即使像 Cython 或
Pyrex 这样的工具,它们仅仅出于扩展的目的而提供了 Python 语言的超集,实际上它们只
是源到源编译器,这种编译器可以使用扩展的类 Python 语法生成 C 代码。
当然,你可以在 Python 中使用任何语言编写的动态/共享库,只要可以这样编译,所以
除了 C 和 C++还是有别的方式。但共享库本质上是通用的。它们可以用于任何支持其加载的语言。因此,即使你使用完全不同的语言(例如说 Delphi 或 Prolog)编写这样的库,如
果不使用 Python/C API,这样的库难以称之为 Python 扩展。
不幸的是,在 C 和 C++中,直接使用 Python/C API 编写自己的扩展是相当苛刻的。不
仅因为它需要很好地理解两种相对难以掌握的语言,同时它也需要非常多的特殊的样板。
有很多重复的代码,仅仅是提供一个接口,这个接口只是使用 Python 及其数据类型粘合你
的实现逻辑而已。不管怎样,了解纯 C 的扩展是如何创建的,是非常有好处的,原因如下。
● 你可以更好地理解 Python 的工作原理。
● 或许有一天,你可能需要调试或维护一个原生的 C/C++扩展。
● 它有助于了解用于构建扩展的高级工具的工作原理。
C 或者 C++扩展的工作原理
只要扩展提供使用 Python/C API 的适配接口,Python 解释器能够从动态/共享库加载它
们。此 API 必须通过 C 头文件-Pythoh.h 引入到到扩展的源代码中,这个头文件通常随着
Python 源代码分发。在许多 Linux 发行版中,这个头文件包含在一个单独的包中(例如,
Debian/Ubuntu 中的 python-dev),但是在 Windows 下,它是默认分发的,可以在 Python 的
安装目录 includes/中找到。
习惯上,Python/C API 随着每个 Python 版本的发布而改变。在大多数情况下,只是对
这些 API 增加新的功能,因此它通常会保持向下兼容。但是,在很多时候,由于应用程序
二进制接口(Application Binary Interface,ABI)的更改,它们不是二进制兼容的。这意味
着扩展必须为每个 Python 版本单独构建。还要注意,不同的操作系统具有互不兼容的 ABIs,
因此这使得实际上不可能为每个可能的环境创建二进制分发。这就是为什么大多数 Python
扩展以源代码形式分发。
自从 Python 3.2,Python/C API 的一个子集已被定义为拥有稳定的 ABIs。然后可以使
用这些有限的 API(具有稳定的 ABI)构建扩展,这些扩展只要构建一次,就可以在任何
高于或等于 3.2 的 Python 版本中正常工作,并且不需要重新编译。不管怎样,这限制了 API
特性的数量,并且不解决旧的 Python 版本的问题,以及二进制形式的扩展在不同操作系统
环境中的分发。所以这是一个折衷,相对于如此低的收益,稳定的 ABI 的代价似乎有点高。
你需要知道的一件事是 Python/C API 是一个限于 CPython 实现的特性。已经做了一些
努力,为扩展提供替代实现(如 PyPI,Jython 或 IronPython),但似乎目前还没有可行的解
决方案。唯一可以轻松处理扩展的可替换 Python 实现是 Stackless Python,因为它实际上只
是 CPython 的修改版本。
在使用 Python 的 C 扩展之前,需要把它编译成共享/动态库,因为显然没有本地方法
可以直接从源代码将 C/C++代码导入到 Python 中。幸运的是,distutils 和 setuptools提供了辅助程序将编译好的扩展定义为模块,因此编译和分发可以使用 setup.py 脚本处
理,就像它们是普通的 Python 包。这是来自官方文档的 setup.py 脚本的一个示例,它处
理带有内置扩展的简单包的打包,如下所示:
from distutils.core import setup, Extension
module1 = Extension(
‘demo’,
sources=[‘demo.c’]
)
setup(
name=‘PackageName’,
version=‘1.0’,
description=‘This is a demo package’,
ext_modules=[module1]
)
一旦按照以上方式做好了准备,在你的分发流程中就需要一个额外的步骤,如下所示:
python setup.py build
这将编译所有由 ext_modules 参数提供的扩展,编译时会根据 Extension()调用
提供的额外的编译器设置进行。将要使用的编译器是你环境中的默认编译器。如果要使用
源分发来分发包,则不需要此编译步骤。在这种情况下,您需要确保目标环境符合所有编
译的前提条件,例如编译器,头文件和链接到二进制文件的附加库(如果你的扩展需要)。
有关打包 Python 扩展的更多详细信息将在后面的部分中介绍。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值