1. 簡介¶
這份參考手冊將會描述 Python 的程式語言特性,而非用於教學。
在我想要盡可能精確表達的同時,除了語法和詞法分析部分,我仍選擇使用英語來描述這些特性,而不是透過形式化的規格。如此一來,這份文件對於一般讀者來說將更容易理解,只是某些意思表達會有模糊之處。因此,如果你是來自火星,並想要僅僅藉由這份文件來重新實作 Python,你可能有些時候必須猜測做出判斷——事實上,你很有可能實作出一個不同的語言。另一方面,如果你已經在使用 Python,並且好奇這個語言的某個特定領域的精確規則為何,那麼你一定能在這份手冊裡找到它們。而如果你想要看到關於這語言更形式化的一個定義,也許你可以自告奮勇——或是發明一台複製機器。:-)
在一份語言的參考文件中加入太多實作細節,是很危險的——這些細節將來可能變化,同一個語言的其他實作也可能有不一樣的運作方式。然而,CPython 是一個廣泛使用的 Python 實作(儘管其他可選的實作也在持續得到更多支持),而有時候它的一些特別古怪之處確實值得提及,尤其當那樣的實作作法帶來了額外限制。基於這個原因,手冊內你會發現簡短的實作細節說明散落在各處。
每一個 Python 實作都附帶內建模組和標準模組。它們都被記錄於 Python 標準函式庫 (Standard Library) 文件中。一些內建模組因為和語言定義有深刻的交互影響,之後也將提及。
1.1. 可選實作¶
儘管已有一個 Python 實作是目前最廣為流傳,仍存在其他種類的實作適合不同需求的族群所使用。
知名的實作如下:
- CPython
以 C 語言開發,是 Python 一開始的實作,同時也是維護程度最好的。新的語言功能通常會先在這裡問世。
- Jython
基於 Java 所實作的 Python。這個實作可以作為針對 Java 應用程式的腳本語言,或是用它來從 Java 函式庫建立應用程式。它也經常用於撰寫 Java 函式庫的測試。如需更多資訊,請參閱 Jython 網站。
- Python for .NET
這個實作實際上使用 CPython 的實作內容,但它是託管式的 .NET 應用程式,也使得 .NET 函式庫可用。它是由 Brian Lloyd 所設計。如需更多資訊,請參閱 Python.NET 首頁。
- IronPython
另一個基於 .NET 的 Python 實作選項。不像 Python.NET,這是一個會產出中繼語言 (IL) 的完整 Python 實作,並會將 Python 程式碼直接編譯為 .NET 組件。它由 Jython 的原始設計者 Jim Hugunin 所設計。如需更多資訊,請參閱 IronPython 網站。
- PyPy
一個完全透過 Python 來撰寫的 Python 實作。它有一些其他實作所沒有的進階特性,像是它支援無堆疊 Python 以及採用即時編譯器。額外資訊可參閱 PyPy 專案網站。
上述每一個實作都和這份手冊裡所描述的 Python 語言有些許不同,可能需要特定的、在標準 Python 文件涵蓋內容以外的資訊才能掌握。如果在使用它們時有需要瞭解更多,請參閱特定實作的相關文件。
1.2. 標示法¶
為了描述詞法分析和語法,我使用了混合 EBNF 和 PEG 的文法標記系統。例如:
name:letter(letter|digit| "_")* letter: "a"..."z" | "A"..."Z" digit: "0"..."9"
在這個例子裡,第一行說明 name 是由一個 letter 接續零或多個 letter、digit 或底線所組成。而 letter 則是 'a' 到 'z'、A 到 Z 之中任一個單一字元;digit 是 0 到 9 之中的單一字元。
每一條規則的開頭即規則名稱(用來識別被定義的規則),接著一個分號 :。分號右側是由下列語法元素所構成的規則定義 :
name:表示另一條規則的名稱。只要可行,它也會是一個連到規則定義的連結。TOKEN:大寫的名稱代表的是 token。就這裡文法定義的目的而言,token 和規則的意義是相同的。
"text"、'text':單引號或雙引號內的文字必須完全相符,不含外面的引號。依據text的意義,會決定使用何種引號 :e1 e2:僅由空白所開的多個項目代表一個序列。這裡,e1之後必須以e2接續。e1 | e2:垂直槓符號用來隔開可匹配的項目。它代表 PEG 的「有序選擇」——如果e1已匹配,那麼e2便不考慮。在傳統的 PEG 文法裡,使用的是斜線/而非垂直槓。如需更多背景細節,可參考 PEP 617。e*:星號表示星號前的項目重複零次或多次。e+:同樣方式,加號表示重複一次或多次。[e]:以方括號包圍的元素意謂零次或一次。換句話說,方括號裡的元素為選擇性的。e?:問號的用途和方括號一樣,表示問號前的項目是選擇性的。(e):括號用於分組。
以下的表示法僅會用於詞法定義。
"a"..."z":兩個字面值字元由三個點隔開,表示在此界定範圍內(含)任一個 ASCII 字元皆合文法。<...>:角括號內的文字片語是對匹配符號(例如,<除了 "\" 以外的任何 ASCII 字元>)的非正式說明,或是在附近段落有解釋的縮寫(例如<Lu>)。
有些定義會採用預查作法,也就是指定位置的元素必須(或必須不)匹配,但不消耗任何輸入:
&e:正向預查,也就是e必須匹配!e:負向預查,也就是e必須不匹配
一元運算子(*、+、?)跟元素的繫結關係最緊密;垂直槓 (|) 的則最鬆散。
空格的用途只在於隔開 token。
通常而言,規則長度都在一行以內,但太長的規則也可以換行表示:
literal: stringliteral | bytesliteral
| integer | floatnumber | imagnumber
或者,規則可以呈現為第一行以分號結束,而每一種可匹配選項皆在新一行以垂直槓開頭表示。例如:
literal: | stringliteral | bytesliteral | integer | floatnumber | imagnumber
這不代表一開始有一個空白匹配選項。
1.2.1. 詞法和語法定義¶
詞法 (lexical) 和語法 (syntactic) 分析是有一些差異的:lexical analyzer 處理的對象是輸入來源的各個字元,而剖析器 (語法分析器)處理的則是詞法分析產生的 tokens 串流。然而在某些時候,這兩個階段的確切分界會是 CPython 實作細節的問題。
實務上,這兩個的差異在於:在詞法定義裡,任何空格都是有影響的。詞法分析器捨棄了那些無法轉換成 token(例如 token.INDENT 或 NEWLINE)的空白。語法定義才接著處理這些 tokens,而非來源字元。
這份手冊裡不管是為了定義還是風格表現,都使用了同樣的 BNF 文法。在下一個章節(詞法分析)裡所有 BNF 的使用都是詞法定義;在那之後的章節裡則是語法定義。