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. 標示法

為了描述詞法分析和語法,我使用了混合 EBNFPEG 的文法標記系統。例如:

name:   letter (letter | digit | "_")*
letter: "a"..."z" | "A"..."Z"
digit:  "0"..."9"

在這個例子裡,第一行說明 name 是由一個 letter 接續零或多個 letterdigit 或底線所組成。而 letter 則是 'a''z'AZ 之中任一個單一字元;digit09 之中的單一字元。

每一條規則的開頭即規則名稱(用來識別被定義的規則),接著一個分號 :。分號右側是由下列語法元素所構成的規則定義 :

  • 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.INDENTNEWLINE)的空白。語法定義才接著處理這些 tokens,而非來源字元。

這份手冊裡不管是為了定義還是風格表現,都使用了同樣的 BNF 文法。在下一個章節(詞法分析)裡所有 BNF 的使用都是詞法定義;在那之後的章節裡則是語法定義。