用_Python_实现_Python_解释器

摘要: Allison 是 Dropbox 的工程师,在那里她维护着这个世界上最大的 Python 客户端网络之一。在去 Dropbox 之前,她是 Recurse Center 的协调人, 是这个位于纽约的程序员深造机构的作者。

Allison 是 Dropbox 的工程师,在那里她维护着这个世界上最大的 Python 客户端网络之一。在去 Dropbox 之前,她是 Recurse Center 的协调人, 是这个位于纽约的程序员深造机构的作者。她在北美的 PyCon 做过关于 Python 内部机制的演讲,并且她喜欢研究奇怪的 bug。她的博客地址是 akaptur.com。

介绍

Byterun 是一个用 Python 实现的 Python 解释器。随着我对 Byterun 的开发,我惊喜地的发现,这个 Python 解释器的基础结构用 500 行代码就能实现。在这一章我们会搞清楚这个解释器的结构,给你足够探索下去的背景知识。我们的目标不是向你展示解释器的每个细节---像编程和计算机科学其他有趣的领域一样,你可能会投入几年的时间去深入了解这个主题。

Byterun 是 Ned Batchelder 和我完成的,建立在 Paul Swartz 的工作之上。它的结构和主要的 Python 实现(CPython)差不多,所以理解 Byterun 会帮助你理解大多数解释器,特别是 CPython 解释器。(如果你不知道你用的是什么 Python,那么很可能它就是 CPython)。尽管 Byterun 很小,但它能执行大多数简单的 Python 程序(这一章是基于 Python 3.5 及其之前版本生成的字节码的,在 Python 3.6 中生成的字节码有一些改变)。

Python 解释器

在开始之前,让我们限定一下“Pyhton 解释器”的意思。在讨论 Python 的时候,“解释器”这个词可以用在很多不同的地方。有的时候解释器指的是 Python REPL,即当你在命令行下敲下 python 时所得到的交互式环境。有时候人们会或多或少的互换使用 “Python 解释器”和“Python”来说明从头到尾执行 Python 代码的这一过程。在本章中,“解释器”有一个更精确的意思:Python 程序的执行过程中的最后一步。

在解释器接手之前,Python 会执行其他 3 个步骤:词法分析,语法解析和编译。这三步合起来把源代码转换成代码对象code object,它包含着解释器可以理解的指令。而解释器的工作就是解释代码对象中的指令。

你可能很奇怪执行 Python 代码会有编译这一步。Python 通常被称为解释型语言,就像 Ruby,Perl 一样,它们和像 C,Rust 这样的编译型语言相对。然而,这个术语并不是它看起来的那样精确。大多数解释型语言包括 Python 在内,确实会有编译这一步。而 Python 被称为解释型的原因是相对于编译型语言,它在编译这一步的工作相对较少(解释器做相对多的工作)。在这章后面你会看到,Python 的编译器比 C 语言编译器需要更少的关于程序行为的信息。

Python 的 Python 解释器

Byterun 是一个用 Python 写的 Python 解释器,这点可能让你感到奇怪,但没有比用 C 语言写 C 语言编译器更奇怪的了。(事实上,广泛使用的 gcc 编译器就是用 C 语言本身写的)你可以用几乎任何语言写一个 Python 解释器。

用 Python 写 Python 既有优点又有缺点。最大的缺点就是速度:用 Byterun 执行代码要比用 CPython 执行慢的多,CPython 解释器是用 C 语言实现的,并做了认真优化。然而 Byterun 是为了学习而设计的,所以速度对我们不重要。使用 Python 最大优势是我们可以仅仅实现解释器,而不用担心 Python 运行时部分,特别是对象系统。比如当 Byterun 需要创建一个类时,它就会回退到“真正”的 Python。另外一个优势是 Byterun 很容易理解,部分原因是它是用人们很容易理解的高级语言写的(Python !)(另外我们不会对解释器做优化 —— 再一次,清晰和简单比速度更重要)

构建一个解释器

在我们考察 Byterun 代码之前,我们需要从高层次对解释器结构有一些了解。Python 解释器是如何工作的?

Python 解释器是一个虚拟机virtual machine,是一个模拟真实计算机的软件。我们这个虚拟机是栈机器stack machine,它用几个栈来完成操作(与之相对的是寄存器机器register machine,它从特定的内存地址读写数据)。

Python 解释器是一个字节码解释器bytecode interpreter:它的输入是一些称作字节码bytecode的指令集。当你写 Python 代码时,词法分析器、语法解析器和编译器会生成代码对象code object让解释器去操作。每个代码对象都包含一个要被执行的指令集 —— 它就是字节码 —— 以及还有一些解释器需要的信息。字节码是 Python 代码的一个中间层表示intermediate representation:它以一种解释器可以理解的方式来表示源代码。这和汇编语言作为 C 语言和机器语言的中间表示很类似。

微型解释器

为了让说明更具体,让我们从一个非常小的解释器开始。它只能计算两个数的和,只能理解三个指令。它执行的所有代码只是这三个指令的不同组合。下面就是这三个指令:

我们不关心词法、语法和编译,所以我们也不在乎这些指令集是如何产生的。你可以想象,当你写下 7 + 5,然后一个编译器为你生成那三个指令的组合。如果你有一个合适的编译器,你甚至可以用 Lisp 的语法来写,只要它能生成相同的指令。

假设


  1. 7 + 5

生成这样的指令集:


  1. what_to_execute = {
  2. "instructions": [("LOAD_VALUE", 0), # the first number
  3. ("LOAD_VALUE", 1), # the second number
  4. ("ADD_TWO_VALUES", None),
  5. ("PRINT_ANSWER", None)],
  6. "numbers": [7, 5] }

Python 解释器是一个栈机器stack machine,所以它必须通过操作栈来完成这个加法(见下图)。解释器先执行第一条指令,LOAD_VALUE,把第一个数压到栈中。接着它把第二个数也压到栈中。然后,第三条指令,ADD_TWO_VALUES,先把两个数从栈中弹出,加起来,再把结果压入栈中。最后一步,把结果弹出并输出。

栈机器

LOAD_VALUE这条指令告诉解释器把一个数压入栈中,但指令本身并没有指明这个数是多少。指令需要一个额外的信息告诉解释器去哪里找到这个数。所以我们的指令集有两个部分:指令本身和一个常量列表。(在 Python 中,字节码就是我们所称的“指令”,而解释器“执行”的是代码对象。)

为什么不把数字直接嵌入指令之中?想象一下,如果我们加的不是数字,而是字符串。我们可不想把字符串这样的东西加到指令中,因为它可以有任意的长度。另外,我们这种设计也意味着我们只需要对象的一份拷贝,比如这个加法 7 + 7, 现在常量表 "numbers"只需包含一个[7]

你可能会想为什么会需要除了ADD_TWO_VALUES之外的指令。的确,对于我们两个数加法,这个例子是有点人为制作的意思。然而,这个指令却是建造更复杂程序的轮子。比如,就我们目前定义的三个指令,只要给出正确的指令组合,我们可以做三个数的加法,或者任意个数的加法。同时,栈提供了一个清晰的方法去跟踪解释器的状态,这为我们增长的复杂性提供了支持。

现在让我们来完成我们的解释器。解释器对象需要一个栈,它可以用一个列表来表示。它还需要一个方法来描述怎样执行每条指令。比如,LOAD_VALUE会把一个值压入栈中。

原文链接

时间: 2024-08-08 10:50:49

用_Python_实现_Python_解释器的相关文章

菜鸟入门_Python_机器学习(2)_最基本统计特性的证明

@sprt *写在开头:博主在开始学习机器学习和Python之前从未有过任何编程经验,这个系列写在学习这个领域一个月之后,完全从一个入门级菜鸟的角度记录我的学习历程,代码未经优化,仅供参考.有错误之处欢迎大家指正. 系统:win7-CPU; 编程环境:Anaconda2-Python2.7,IDE:pycharm5; 参考书籍: <Neural Networks and Learning Machines(Third Edition)>- Simon Haykin; <Machine L

python实现爬取千万淘宝商品的方法_python_脚本之家

分享到 一键分享 QQ空间 新浪微博 百度云收藏 人人网 腾讯微博 百度相册 开心网 腾讯朋友 百度贴吧 豆瓣网 搜狐微博 百度新首页 QQ好友 和讯微博 更多... 百度分享 python实现爬取千万淘宝商品的方法 作者:mingaixin 字体:[增加 减小] 类型:转载 这篇文章主要介绍了python实现爬取千万淘宝商品的方法,涉及Python页面抓取的相关技巧,需要的朋友可以参考下 本文实例讲述了python实现爬取千万淘宝商品的方法.分享给大家供大家参考.具体实现方法如下: ? 1 2

菜鸟入门_Python_机器学习(3)_回归

@sprt *写在开头:博主在开始学习机器学习和Python之前从未有过任何编程经验,这个系列写在学习这个领域一个月之后,完全从一个入门级菜鸟的角度记录我的学习历程,代码未经优化,仅供参考.有错误之处欢迎大家指正. 系统:win7-CPU; 编程环境:Anaconda2-Python2.7,IDE:pycharm5; 参考书籍: <Neural Networks and Learning Machines(Third Edition)>- Simon Haykin; <Machine L

菜鸟入门_Python_机器学习(4)_PCA和MDA降维和聚类

@sprt *写在开头:博主在开始学习机器学习和Python之前从未有过任何编程经验,这个系列写在学习这个领域一个月之后,完全从一个入门级菜鸟的角度记录我的学习历程,代码未经优化,仅供参考.有错误之处欢迎大家指正. 系统:win7-CPU; 编程环境:Anaconda2-Python2.7,IDE:pycharm5; 参考书籍: <Neural Networks and Learning Machines(Third Edition)>- Simon Haykin; <Machine L

微信_跳一跳辅助程序_Python_(带GitHub项目地址)

1.安装Python(推荐3.6) https://www.python.org/downloads/2.在github上下载脚本 [github项目地址](https://github.com/wangshub/wechat_jump_game) 3.安装ADB+配置PATH[adb全称Android Debug Bridge调试桥:PC与手机的链接工具] http://adbshell.com/downloads4.链接手机(限安卓)或安卓模拟器 DOS窗口输入adb devices验证设备

解释器模式 Interpreter

代码例子 参考 1.解释器模式定义 给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子. 说明:解释器模式设计到文法规则和抽象语法树. 2.解释器模式的结构 解释器模式包含四个角色: 1)抽象表达式(AbstractExpress):声明抽象的解释操作,它是所有终结符表达式和非终结符表达式的公共父类. 2)终结符表达式(TerminalExpress):是抽象表达式的子类,实现了与文法中的终结符相关联的解释操作,句子中的每一个终结符都是该类的一个实例.

【译】使用 Python 编写虚拟机解释器

原文地址:[Making a simple VM interpreter in Python](https://csl.name/post/vm/) **更新:根据大家的评论我对代码做了轻微的改动.感谢 robin-gvx. bs4h 和 Dagur,具体代码见[这里](https://github.com/cslarsen/python-simple-vm)** Stack Machine 本身并没有任何的寄存器,它将所需要处理的值全部放入堆栈中而后进行处理.Stack Machine 虽然简

怎样写一个解释器

我这个标题起的有一些不厚道,与大神的文章同名,倒不是因为我自比大神,是因为这两个说的是同一个东西. 简单地说,这篇是我在学习了 eopl 前面三章之后,把里面课后作业的解释器的构建过程,拿出来给团队同事们介绍一遍,并且从两条最简单的语法规则开始(输入一个字符串,返回一个数字),逐步完成书中介绍的 ``let-lang'' 的全部语法: 在这个简单的解释器里面,介绍了 AST, environement, closure 等名词,会使你了解一些平时困扰你的问题,比如 pyhton 的 lambda

设计模式之解释器模式

定义:给定一个语言,定义它的方法的一种表示,并定义一个解释器.这个解释器使用该表示解释语言中的句子 结构图: 演示样例代码: public abstract class AbstractExpression { public abstract void interpret(Context context); } public class NonterminalExpression extends AbstractExpression { @Override public void interpr