编程学习网 > 编程语言 > Python > PythoC:一种从 Python 生成 C 代码的新方法
2025
12-12

PythoC:一种从 Python 生成 C 代码的新方法


Python 和 C 的共通之处比表面看起来要更多。Python 解释器的参考版本便用 C 语言编写的,许多为 Python 编写的第三方库也封装了C 代码。此外,还可以从 Python 生成 C 代码。

使用 Python 生成 C 代码通常需要像Cython这样的库,这些库使用类型注释的 Python 代码为 Python 生成 C 扩展模块。

现在,有一个名为PythoC 的新项目采用了不同的方法。它使用类型提示的 Python 以编程方式生成 C 代码——但主要用于独立用途,并且比 Cython 具有更多的编译时代码生成功能。

PythonC 的开发者用“C 级运行时,Python 驱动的编译时”来描述他们的开发理念。该项目仍处于早期阶段,但已有的功能足以值得开发者来关注。

一个基本的 Python 程序

以下是一个根据 Python 示例改编的简单程序:


要指定模块中哪些函数需要编译成 C 代码,可以使用 PythonC 的@compile装饰器,并为结果和每个参数提供类型提示。

注意,你需要导入 PythonC 自带的 ` i32int` 类型提示,而不是使用 Python 原生的 `int` 类型int提示。这意味着使用的是机器原生的整数,而不是 Python 的任意大小整数。

运行此程序后,延迟一段时间后会得到输出结果。C 代码每次执行程序时30都会即时编译,因此会有些延迟。PythoC 目前还没有像 Cython 那样,在从 Python 调用时重用已编译代码的机制。

乍一看,这似乎是一个相当大的限制。但实际上,这正是它的优势所在:你可以将 PythoC 用作 C 程序的代码生成系统,生成独立运行的 C程序,而不是将 C模块导入 Python。

生成独立的 C 程序

这是同一程序的全新版本,行为却有所不同。



首先,你会注意到的是底部的代码块——这个compile_to_executable()函数正所谓恰如其名。调用它后,当前模块将被编译成一个同名的可执行文件,其中@compile包含所有被 `-` 装饰的函数。

另一个区别是,该函数现在与C 程序中的函数main()具有相同的名称。这意味着编译后的可执行文件将自动使用该名字作为其执行入口点。

最后,运行此程序时,生成的可执行文件(位于build子目录中)不会自动运行;我们须手动运行它。此程序的目的是构建一个独立的C 程序,其外观与用 C 语言手动编写的程序完全相同,但语法却与 Python 类似。

PythonC 对 C 语言特性的模拟

除了少数例外情况外,PythoC 可以生成充分利用 C 语言特性集和运行时的代码。

我们已经了解了如何使用类型注解来指示基本数据类型。同样,可以使用ptr[T]注解来描述指针(如上所示),并用array[T, N]它来表示类型为 T 的 N 维数组。

我们可以通过修饰 Python 类来创建结构体、联合体和枚举,所有常用的运算符和控制流操作(除了 `__include__` goto)都适用。对于`__include__` switch/case,只需使用 `__include__` match/case,尽管它不支持回退情况。

另一个缺失的功能是可变长度数组。在 C 语言中,只有 C11 及更高版本才支持此功能,而且编译器对它的支持是可选的,因此 PythonC 目前不支持它也并不奇怪。

编译时代码生成

Cython 可以用于编译时代码生成,这表示着您可以生成不同类型的 C 代码,甚至可以根据编译时的情况回退到 Python 代码。但是 PythonC 的编译时代码生成功能是 Cython 所不具备的。

以下是 Python 文档中的一个代码示例:


make_point(T)函数接受类型注解(i32`@ type`、 f64`@type`),并在编译时生成类Pointadd_points函数的类型特化版本。` suffix@type` 参数@compile表示“更改生成对象的名称,使其名称中包含类型信息”——例如,`@type`Point会变成 ` @type`Point_i32和 `@ Point_i64type`,这在 C 语言中是区分同一函数的不同类型签名的一种方法。

此外,还可以结合运行时分发来实现多态性

内存安全功能

C语言手动内存管理可能引发的各种bug,对于任何使用过这门语言的人来说都耳熟能详。Cython提供了内存安全机制来解决这个问题,而Python则提供了独特的基于类型的特性。

其中一项特性称为linear(线性类型)linear导入该类型可以生成一个“证明”,通常用于内存分配,该证明必须在释放同一块内存时被“消耗”。如果consume(prf)每个内存分配都没有匹配的证明prf=linear(),PythonC 编译器将生成一个编译时错误。上面链接的文档展示了如何创建简单的lmalloc()`/`lfree()函数来安全地分配和释放内存。虽然没有规定你必须使用线性类型而不能手动使用malloc()`/ free()`,但线性类型可以自动执行许多手动检查,并将检查集中在编译时而不是运行时。

另一种基于类型的安全特性是细化类型。其思想是,你可以定义一个函数来执行某种检查(例如,检查空指针),并返回一个布尔值结果。然后,你可以使用该refine()函数传递一个值,并获取该函数特有的类型refined[func]。这使得编译器能够确保该类型在返回之前必须经过某种处理,并且允许在代码的单个位置处理常见的检查(例如,检查非空指针)。

Cython 的类型系统主要用于直接模拟 C 语言的行为,因此不包含类似的功能。

PythonC 的未来发展

PythoC 目前仍处于早期开发阶段,其未来的发展方向相对开放。

一种可能性是,它可以在运行时与 Python 更紧密地集成。例如,@cached装饰器可以预先编译模块一次,然后在 Python 内部调用时重用已编译的模块,而无需每次运行时都重新编译。

当然,这还需要与 Python 现有的模块构建系统集成。虽然这种程度的集成可能并非该项目的目标,但它将使 PythoC 对那些需要集成 C 和 Python 的开发者来说更加实用。

以上就是“PythoC:一种从 Python 生成 C 代码的新方法的详细内容,想要了解更多Python教程欢迎持续关注编程学习网。

扫码二维码 获取免费视频学习资料

Python编程学习

查 看2022高级编程视频教程免费获取