Python 高手编程系列八百六十八:CFFI

CFFI 是 Python 的外部函数接口,是 ctypes 的一个替代品。它不是标准库的一部分,
但是它作为一个 cffi 包,可以很容易地从 PyPI 上获得。它不同于 ctypes,因为它更加强调重用纯 C 代码,而不是在单个模块中提供大量的 Python API。它的方式更复杂,并且
还有一个特性,它允许你使用 C 编译器将集成层的某些部分自动编译为扩展。因此,它可
以用作填补 C 扩展和 ctypes 之间差距的混合解决方案。
因为它是一个非常大的项目,不可能用很少的段落就能快速地介绍它。另一方面,不
多说一些关于它的使用是一件非常遗憾的事情。我们已经讨论了使用 ctypes 从标准库集
成 qsort()函数的一个示例。因此,显示这两个解决方案之间的主要区别的最好方法是使
用 cffi 重新实现相同的示例。而我希望,一段代码胜过千言万语,如下所示:
from random import shuffle
from cffi import FFI
ffi = FFI()
ffi.cdef(“”"
void qsort(void *base, size_t nel, size_t width,
int (*compar)(const void , const void ));
“”")
C = ffi.dlopen(None)
@ffi.callback("int(void
, void
)")
def cffi_int_compare(a, b):

回调签名需要类型的精确匹配,

这涉及到比 ctypes 更少的魔法,

但需要更详细,更明确的转型。

int_a = ffi.cast(‘int*’, a)[0]
int_b = ffi.cast(‘int*’, b)[0]
print(" %s cmp %s" % (int_a, int_b))

根据快速排序的规范,应该这样返回::

* 如果 a 小于 b,则小于 0

* 如果 a 等于 b,则等于 0

* 如果 a 大于 b,则大于 0

return int_a - int_b
def main():
numbers = list(range(5))
shuffle(numbers)
print("shuffled: ", numbers)
c_array = ffi.new(“int[]”, numbers)
C.qsort(

指向被排序的数组的指针

c_array,

数组的长度

len(c_array),

数组中单个元素的大小

ffi.sizeof(‘int’),

回调(指向 C 比较函数的指针)

cffi_int_compare,
)
print("sorted: ", list(c_array))
if name == “main”:
main()
小结
本章解释了本书中最高级的一个主题。我们讨论了构建 Python 扩展的原因和工具。我
们从编写纯 C 扩展开始,这些扩展仅依赖于 Python/C API,然后使用 Cython 重新实现它们,
用以说明选择合适的工具,构建扩展是如此的容易。
还有一些原因,以艰难的方式构建扩展,只使用纯 C 编译器和 Python.h 头文件。总
之,最好的建议是使用工具,如 Cython 或 Pyrex(这里不是推荐),因为它可以提高代码库
的可读性与可维护性。它还将为你节省由于不当的引用计数和内存管理导致的大多数问题。
我们对扩展的讨论以 ctypes 和 CFFI 的介绍结束,它们可以作为解决集成共享库问
题的另一种方法。因为他们不需要在编写自定义扩展时从编译的二进制文件中调用函数,
它们应该是你选择的工具,特别是如果你不需要使用自定义 C 代码。
在下一章中,我们将从低级编程技术中休息一段时间,然后深入探讨同样重要的主题
即代码管理和版本控制系统。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值