第19章 PyPy
PyPy是一个Python实现的动态语言实现框架。
本章假定读者熟悉如字节码和常量叠算等有关解释器和编译器的基本概念。
19.1. 一点历史
Python是一种高层次动态编程语言。它是由荷兰程序员Guido van Rossum在20世纪80年代末发明的。Guido最初的实现是一个用C语言编写的传统的字节解释器,人称CPython。现在有许多其他的Python实现。其中最引人注目的有用Java编写的并允许Java代码接口的Jython,用C#编写并允许和微软.NET框架接口的IronPython,以及本章的主题PyPy。 CPython的仍然是使用最广泛的实现,也是当前唯一支持下一代Python 3语言的实现。本章将谈谈让PyPy与其他Python实现乃至其他任何动态语言实现都有所不同的一些设计决策。
19.2. PyPy概览
除了微不足道的少量C代码,PyPy完全是用Python写成的。PyPy代码树包含两个主要部分:Python解释器和RPython翻译工具链。 Python解释器是面向程序员的运行库,人们使用PyPy来调用Python实现。它实际上是用Python的一个子集——限制Python(通常缩写为RPython)写成的。用RPython编写Python解释器的目的是让解释器可以输出给PyPy的另一个重要组成部分——RPython翻译工具链。 RPython翻译器会把RPython代码转换为一个选定的低级语言,最常用的是C。这使得PyPy成为一个自我托管的实现,也就是说它是用它自己实现的语言写成的。我们在本章后文中还会看到,RPython翻译也让PyPy成为一个普适的动态语言实现框架。
PyPy强大的抽象使之成为最灵活的Python实现。从不同的垃圾回收到各种翻译优化参数,它有近200个不同的配置选项。
19.3. Python解释器
由于RPython是Python的真子集,PyPy Python解释器可以不经翻译地在另一个Python实现上运行。当然,这会非常慢,但这样我们就可以快速测试解释器的变化。这也让我们可以使用普通的Python调试工具来调试解释器。 PyPy的解释器的大多数测试可以同时运行在无翻译和有翻译的解释器上。这让开发时的快速测试成为可能,并保证了有翻译和无翻译的解释器的行为一致。
在大多数情况下,PyPy Python解释器的细节和CPython非常类似,PyPy和CPython在解释时使用的字节码和数据结构几乎完全一样。两者之间的主要区别在于PyPy有一种很聪明的抽象,称为对象空间(简称objspaces)。objspace封装了代表和操作Python数据类型的所有知识。例如,对两个Python对象执行二元操作或获取对象的一个属性,都完全由objspace处理。这让解释器无需知道Python对象的任何实现细节。字节码解释器吧Python对象看成是黑盒子,并在需要操作它们时调用objspace方法。例如,下面是BINARY_ADD
机器码的一个粗糙的实现,在两个对象用+运算符结合的时候会调用它。请注意解释器如何不去检查运算符;所有处理都立即被委托给objspace。
def BINARY_ADD(space, frame):
object1 = frame.pop() # pop left operand off stack
object2 = frame.pop() # pop right operand off stack
result = space.add(object1, object2) # perform operation
frame.push(result) # record result on stack