Python解释器的探讨:第一部分函数对象
最近三个月,我和Ned Batchelder花费了大量时间在开发byterun。这个项目byterun(https://github.com/nedbat/byterun)是使用python开发的python字节码的解释器。开发解释器byterun过程中,让我学习到很多东西,以及带来很大的乐趣。在本文系列里,我将带你来体验一下我的开发乐趣,以及使用byterun是非常高兴的事情。不过,在体验快乐之前,先要理解一些基础的知识,就像做运动之前先来暖身一下:对python内部实现有一个整体的了解,以便我们知道解释器是什么东西,它做什么用的,它不能做什么。
本文假定你知道有python这个东西,跟我三个月以前是一样的,除了这个什么都不知道,别说什么python内部实现了。
值得注意的是:本文主要关注和讨论的都是在python2.7版本基础上进行。其实python3.0版本的解释器也差不了太多,与前面版本类似。主要是一些语法和命名不同样,基于底层的内容完全是可以往python3.0版本进行套用的。
python是怎么样工作呢?
我们将从高级的交互界面开始来了解python内部是怎么样工作的。当你在python的交互解释器里输入一行代码,然后运行它,那解释器在做了些什么呢?
~ $ python
Python 2.7.2 (default, Jun 20 2012, 16:23:33)
[GCC 4.2.1 Compatible Apple Clang 4.0 (tags/Apple/clang-418.0.60)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> a = "hello"
当你输入那行代码之后,按下回车键时,这时python解释器发生了四件事情:词法分析、语法分析、编译生成字节码和解释执行字节码。词法分析做的事情就是把你输入的代码分析之后,生成一个一个的单词(token)。语法分析做的事情就是分析这些单词,然后根据单词之间相互的关系生成一个合适表达它们之间关系的结构(在这里是生成AST抽象语法树)。编译生成代码阶段就是把AST结构生成一个或多个代码对象,而代码对象里已经变成字节码和数据。最后,解释执行阶段把每个代码对象里的字节码进行运行。
在今天本文里,我不打算讨论词法分析、语法分析或编译生成代码,因为对这些阶段过程,我都不懂,没办法通过我的语言表达出来。反而我假定这些都运行正确,并且能够生成合适的python代码对象,以便给解释器进行运行。
在我们讨论代码对象之前,先来进行一些综合的背景知识介绍。在本文系列文章里,我们将会讨论函数对象、代码对象和字节码。这三者之间是完全不同的,接着下来先会讨论函数对象。虽然不理解函数对象也可以理解解释器的内部功能,但是我想要强调的是函数对象和代码是两个不同的东西,函数对象更加特别一些。
函数对象
你也许经常听说到函数对象,因为人们经常谈论它们,比如说“函数对象是最重要的一类对象”或者“python代码主要由函数对象构成”。来,让我们先看看函数对象长得怎么样:
>>> def foo(a):
... x = 3
... return x + a
...
>>> foo
<function foo at 0x107ef7aa0>
“函数对象是最重要的一类对象”的意思就是说函数是对象,不仅像list对象或者MyObject对象一样。由于foo是一个函数对象,因此可以直接使用foo,而不必调用它运行(应理解foo和foo()之间差别)。我们可以把foo作一个参数传递给函数使用,或者把函数对象赋值给另一个变量(命名,other_function = foo)。由于函数作为一类对象来对待,那么很多功能与普通对象是一样的。
在第二部分,我们将讨论更低级的代码对象。
参考:
http://akaptur.com/blog/2013/11/15/introduction-to-the-python-interpreter/
蔡军生 QQ:9073204 深圳