標籤:milang python 編譯器
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 深圳
Python解譯器的探討:第一部分函數對象