在最近三個月,我和Ned Batchelder用了很多時間在做 byterun。它是用Python寫的Python位元組碼直譯器。做 byterun 的過程十分有趣,也讓我收穫了很多知識。在這個系列文章的結尾,我將試著讓你相信:你也能輕鬆愉快地“玩” byterun。但在那之前,我們需要做一些準備工作:大概瞭解python內部是如何工作的。這樣我們才能理什麼是直譯器,它能做什麼以及它不能做什麼。
這個系列文章是面向水平和三個月前的我相似的讀者。也就是你瞭解python,但對它的內部工作一無所知。
提示:本文將基於 Python 2.7 , Python 3 中的直譯器也非常相似。雖然我會忽略兩個版本之間的語法和命名差異,但我這個系列同樣可以試用於 Python3。
Python是如何工作的?
我們將從高層開始瞭解python的內部工作。你在你的python REPL裡執行一行程式碼之後,它是如何工作的呢?
1 2 3 4 5 |
~ $ 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" |
當你敲下return鍵的時候,python完成了以下四步:詞法分析、句法分析、編譯、解釋。詞法分析的工作就是將你剛才輸入的那行程式碼分解為一些符號token(譯者注:包括標示符,關鍵字,數字, 操作符等)。句法分析程式再接收這些符號,並用一種結構來展現它們之間的關係(在這種情況下使用的抽象語法樹)。然後編譯器接收這棵抽象語法樹,並將它轉化為一個(或多個)程式碼物件。最後,直譯器逐個接收這些程式碼物件,並執行它們所代表的程式碼。
主要是因為我現在對這些步驟一竅不通,所以我並不打算詳解詞法分析、句法分析和編譯。但是,我們假設這些步驟都正常執行,並且能夠提供給直譯器一個合適的python程式碼物件來完成解釋工作。
在我們談論程式碼物件之前,我想先解答一些常見的疑惑。我們將在這個系列文章中講解函式物件、程式碼物件以及位元組碼。它們是完全不同的概念。我們就從函式物件談起吧。雖然我們不需要了解函式物件到達直譯器的過程,但是我想強調函式物件和程式碼物件是截然不同的(另外,函式物件超棒!)。
函式物件
你也許對“函式物件”早有耳聞。當談到“函式是最好的物件”或者“Python有著最棒的函式”時,人們總會提起它。那我們就來看一個函式物件吧。
1 2 3 4 5 6 |
>>> def foo(a): ... x = 3 ... return x + a ... >>> foo <function foo at 0x107ef7aa0> |
“函式是最好的物件”說明函式是一種物件。它就如同一個列表或者舉個例子來說 :MyObject 就是一個物件。既然 foo 是一個物件,那麼我們就能在不呼叫它的情況下使用它(也就是說,foo 和 foo() 是大相徑庭的)。我們能夠將 foo 當作一個引數傳遞給另一個函式或者賦值給一個新函式名( other_function = foo )。有了如此棒的函式,一切皆為可能!
在第二部分,我們將著眼於下一層次——程式碼物件。