### 2. 詞法分析
Python程序由*解析器*讀取。輸入到解析器中的是由*詞法分析器*生成的*詞符*流。本章講述詞法分析器如何把一個文件拆分成詞符。
Python程序的文本使用7比特ASCII字符集。
2.3版中新增:可以使用編碼聲明指出字符串字面值和注釋使用一種不同于ASCII的編碼。
為了和舊的版本兼容,如果發現8比特字符,Python只會給出警告。修正這些警告的方法是聲明顯式的編碼,或者對非字符的二進制數據字節使用轉義序列。
運行時的字符集取決于與程序連接的I/O設備,但通常都是ASCII的超集。
**未來兼容性的注意事項:**可能會假設8比特字符的字符集是ISO Latin-1(ASCII字符集的超集,覆蓋了大部分使用拉丁字母的西方語言),但是在未來Unicode文本編輯器可能變得通用。這些編輯器通常使用UTF-8編碼,它也是ASCII的超集,但是序數在128-255之間的字符的用法非常不一樣。關于這個主題還沒有一致的意見,假設是Latin-1或UTF-8都不明智,即使當前的實現似乎傾向于Latin-1。源文件的字符集和運行時的字符集都適用。
### 2.1. 行結構
一個Python程序被分割成若干*邏輯行*。
#### 2.1.1. 邏輯行
邏輯行的結束由NEWLINE詞符表示。語句不能跨越邏輯行的邊界除非語法允許NEWLINE(例如,復合語句的語句之間)。通過遵循顯式或隱式的*行連接*規則,一個邏輯行由一個或多個*物理行*構成。
#### 2.1.2. 物理行
一個物理行是一個被行結束序列終止的字符序列。在源文件中,任何標準平臺的行終止序列都可以使用 - Unix方式使用ASCII的LF(換行),Windows方式使用ASCII序列CR LF(回車和換行),舊的Macintosh方式使用ASCII的CR(回車)字符。
在嵌入Python時,對于換行符源代碼字符串應該使用標準C的習慣傳遞給Python API(代表ASCII LF的\n字符是行終止符)。
#### 2.1.3. 注釋
注釋以非字符串字面值中的井號字符(#)開始,在物理行的末尾結束。除非引起隱式的行連接規則,否則注釋意味著邏輯行的結束。語法會忽略注釋;它們不是詞符。
#### 2.1.4. 編碼聲明
如果Python腳本的第一行或者第二行的注釋匹配正則表達式coding[=:]\s*([-\w.]+),那么這行注釋將作為編碼聲明處理;該表達式的第一個分組指出源文件編碼的名字。建議的表達式形式是
~~~
# -*- coding: <encoding-name> -*-
~~~
它也能被GNU Emacs識別,或者
~~~
# vim:fileencoding=<encoding-name>
~~~
它能被Bram Moolenaar的VIM識別。除此之外,如果文件開始幾個字節是UTF-8的字節順序標記('\xef\xbb\xbf'),聲明的文件編碼將是UTF-8(這個特性也被微軟的**notepad**和其它編輯器支持。)
如果聲明了編碼,那么編碼的名字必須能夠被Python識別。編碼將用于所有的詞法分析,特別是尋找字符串的結束,和解釋Unicode字面值的內容。字符串字面值會被轉換成Unicode來做語法分析,然后在解釋開始之前被轉換回它們初始的編碼。編碼聲明必須出現在它自己單獨的一行上。
#### 2.1.5. 顯式的行連接
兩個或多個物理行可以使用反斜杠字符(\)連接成一個邏輯行,方式如下:當一個物理行以一個不是字符串字面值或注釋中的反斜杠結束時,它會和接下來的一行連接形成一個單獨的邏輯行,反斜杠和后面的換行符會被刪掉。例如:
~~~
if 1900 < year < 2100 and 1 <= month <= 12 \
and 1 <= day <= 31 and 0 <= hour < 24 \
and 0 <= minute < 60 and 0 <= second < 60: # Looks like a valid date
return 1
~~~
以反斜杠結束的行不能帶有注釋。反斜杠不能延續注釋。反斜杠不能延續除了字符串字面值以外的詞符(即不是字符串字面值的詞符不能使用反斜杠分割跨多個物理行)。一行中位于字符串字面值以外其它地方的反斜杠是非法的。
#### 2.1.6. 隱式的行連接
圓括號、方括號以及花括號中的表達式可以分割成多個物理行而不使用反斜杠。例如:
~~~
month_names = ['Januari', 'Februari', 'Maart', # These are the
'April', 'Mei', 'Juni', # Dutch names
'Juli', 'Augustus', 'September', # for the months
'Oktober', 'November', 'December'] # of the year
~~~
隱式的續行可以帶注釋。續行的縮進不重要。允許空白的續行。隱式的續行之間沒有NEWLINE詞符。隱式的續行也可以發生在三引號的字符串中(見下面):在這種情況下它們不可以帶注釋。
#### 2.1.7. 空白行
只包含空格符、制表符、換頁符和注釋的邏輯行會被忽略(即不會有NEWLINE詞符生成)。在交互式輸入語句時,空白行的處理可能不同,這取決于read-eval-print循環的實現。在標準實現中,一個完全的空白邏輯行(即一個不只是包含空格或注釋的邏輯行)會終止多行語句。
#### 2.1.8. 縮進
邏輯行開始的前導空白(空格和制表符)用來計算行的縮進層級,然后用它決定語句的分組。
首先,制表符被替換(從左到右)成一至八個空格,這樣包括替換后的字符的總數是八的整數(這是為了和Unix 使用一樣的規則)。非空白字符之前的空格總數決定該行的縮進。縮進不可以使用反斜杠分割成多個物理行;直到第一個反斜杠處的空白決定了縮進。
**跨平臺兼容性的注意事項:**由于非UNIX平臺上的文本編輯器的天性,在一個源文件中縮進混合使用空格和制表符是不明智的。還應該注意到不同的平臺可能明確地限定最大縮進的層級。
行的開始可能會出現換頁符;它將被上述縮進的計算忽略。在前導空白其它地方出現的換頁符的作用沒有定義(例如,它們可能會重置空格的數量為零)。
連續行的縮進層級用于生成INDENT和DEDENT詞符,這個過程使用了棧,如下所述。
在讀入文件第一行之前, 一個零被壓入堆棧中;它將再也不會被彈出。壓入堆棧中的數字將永遠從底部往頂部增長。在每一個邏輯行的開始,該行的縮進層級會與棧頂比較。如果相等,什么都不會發生。如果大于棧頂,將其壓入棧,并生成一個INDENT詞符。如果小于棧頂,它*必須*是堆棧中已存在的數字中的一個;棧中所有大于它的數都將被彈出,并且每個彈出的數字都生成一個DEDENT詞符。到達文件尾時,棧中剩下的每一個大于零的數字也生成一個DEDENT詞符。
這兒是一個正確縮進的Python代碼片段的例子(雖然有點亂):
~~~
def perm(l):
# Compute the list of all permutations of l
if len(l) <= 1:
return [l]
r = []
for i in range(len(l)):
s = l[:i] + l[i+1:]
p = perm(s)
for x in p:
r.append(l[i:i+1] + x)
return r
~~~
下面的例子展示了各種縮進錯誤:
~~~
def perm(l): # error: first line indented
for i in range(len(l)): # error: not indented
s = l[:i] + l[i+1:]
p = perm(l[:i] + l[i+1:]) # error: unexpected indent
for x in p:
r.append(l[i:i+1] + x)
return r # error: inconsistent dedent
~~~
(事實上;前三個錯誤是由解析器發現的;僅僅最后一個錯誤是由詞法分析器找到的 -- returnr 的縮進層級與堆棧中彈出的數字沒有匹配的層級。
#### 2.1.9. 詞符之間的空白
除非位于邏輯行起始處或者字符串字面值當中,空格、制表符和換頁符這些空白字符可以等同地用于分隔詞符。空白僅當兩個詞符連接在一起可以理解成一個不同的詞符時才需要(例如,ab是一個詞符,但a b是兩個詞符)。
### 2.2. 其它的詞符
除了NEWLINE、INDENT和DEDENT,還存在以下幾類詞符:*標識符*、*關鍵字*、*字面值*、*操作符*和*分隔符*。空白字符(前面討論的斷行符除外)不是詞符,而是用于分隔詞符。有歧義存在時,詞符由形成合法詞符的最長字符串組成(自左向右讀取)。
### 2.3. 標識符和關鍵字
標識符(也稱為*名字*)由以下詞法定義描述:
~~~
identifier ::= (letter|"_") (letter | digit | "_")*
letter ::= lowercase | uppercase
lowercase ::= "a"..."z"
uppercase ::= "A"..."Z"
digit ::= "0"..."9"
~~~
標識符長度沒有限制。區分大小寫。
#### 2.3.1. 關鍵字
以下標識符用作保留字,或者叫做語言的*關鍵字*,并且不能作為普通的標識符使用。它們必須像下面那樣準確拼寫:
~~~
and del from not while
as elif global or with
assert else if pass yield
break except import print
class exec in raise
continue finally is return
def for lambda try
~~~
版本2.4 中的變化:[None](# "None")成為一個常量并且被編譯器識別為內建對象[None](# "None")的名字。盡管不是關鍵字,你也不可以給它賦值一個不同的對象。
版本2.5 中的變化:使用[as](#)和[with](#)作為標識符會引發警告。要使用它們作為關鍵字,需啟用with_statement這個未來特性。
版本2.6 中的變化:[as](#)和[with](#)成為真正的關鍵字。
#### 2.3.2 保留類別的標識符
有幾種特定類別的標識符(關鍵字除外)具有特殊的含義。這些類別有標志性的模式就是開始和尾部的下劃線:
_*
不會被frommoduleimport*導入。_這個特殊的標識符用于在交互式解釋器中存儲上一次計算的結果;它存儲在[__builtin__](# "__builtin__: The module that provides the built-in namespace.")模塊。不在交互式模式時,_沒有特別的含義且是未定義的。參看[*import 語句*](#)一節。
注意
名字_經常用于國際化;關于這個慣例的更多信息請參考[gettext](# "gettext: Multilingual internationalization services.")模塊的文檔。
__*__系統定義的名字。這些名字由解釋器及其實現(包括標準庫)定義。這些系統定義的名字在[*特殊方法的名字*](#)一節和其它地方討論。未來版本的Python 可能會定義更多的系統名字。無論什么情況,*任何*不遵守明確的文檔使用說明的__*__使用,都可能會帶來破壞而沒有警告。__*類私有變量。這種類別的名字,在類定義的語境中使用時,會被使用一種變形的形式重寫以避免基類和繼承類的“私有”屬性之間的沖突。參考[*標識符(名稱)*](#)一節。
### 2.4. 字面值
字面值是某些內建類型常量的標寫法。
#### 2.4.1. 字符串字面值
字符串字面值由以下詞法定義描述:
~~~
stringliteral ::= [stringprefix](shortstring | longstring)
stringprefix ::= "r" | "u" | "ur" | "R" | "U" | "UR" | "Ur" | "uR"
| "b" | "B" | "br" | "Br" | "bR" | "BR"
shortstring ::= "'" shortstringitem* "'" | '"' shortstringitem* '"'
longstring ::= "'''" longstringitem* "'''"
| '"""' longstringitem* '"""'
shortstringitem ::= shortstringchar | escapeseq
longstringitem ::= longstringchar | escapeseq
shortstringchar ::= <any source character except "\" or newline or the quote>
longstringchar ::= <any source character except "\">
escapeseq ::= "\" <any ASCII character>
~~~
上面產生式中沒有表示出來一個的語法限制是, 在[stringprefix](#)與其余字符串字面值之間不允許出現空白字符。字符集由編碼聲明定義;如果源文件中沒有指定編碼聲明,則為ASCII;參考[*編碼聲明*](#)一節。
用簡單的中文來描述就是:字符串字面值可以包含在配對的單引號(')或雙引號(")中。它們也可以包含在配對的三個單引號或雙引號組中(這些字符串一般稱為*三引號字符串*)。反斜杠(\) 用于轉義具有特殊意義的字符,例如換行、反斜杠本身或者引號。字符串字面值可以加一個前綴字母'r' 或者'R';這些字符串稱為*原始字符串* 并且使用不同的規則解釋反斜杠轉義的序列。前綴'u'或'U'使得字符串成為一個Unicode字符串。Unicode 字符串使用由Unicode 協會和ISO 10646定義的Unicode 字符集。Unicode 字符串中有效的一些額外轉義序列會在下面描述。前綴'b'或'B'在Python 2中被忽略;在Python 3中,它表示那個字面值應該是一個字節型字面值(例如,用2to3自動轉換代碼的時候)。前綴'u'或'b'后面可以跟隨一個前綴'r'。
在三引號字符串中,沒有轉義的換行和引號是允許的(并且會被保留),除非三個未轉義的引號終止了字符串。(引號指用于開始字符串的字符,例如' 或"。)
除非出現前綴'r' 或'R',否則字符串中的轉義序列依照類似標準C 使用的規則解釋。可識別的轉義序列有:
| 轉義序列 | 含義 | 說明 |
|-----|-----|-----|
| \newline | 忽略 | ? |
| \\ | 反斜杠 (\) | ? |
| \' | 單引號 (') | ? |
| \" | 雙引號 (") | ? |
| \a | ASCII響鈴(BEL) | ? |
| \b | ASCII退格(BS) | ? |
| \f | ASCII換頁(FF) | ? |
| \n | ASCII換行(LF) | ? |
| \N{name} | Unicode數據庫中名為*name*的字符(Unicode only) | ? |
| \r | ASCII回車(CR) | ? |
| \t | ASCII水平制表(TAB) | ? |
| \uxxxx | 16位的十六進制值為*xxxx*的字符(Unicode only) | (1) |
| \Uxxxxxxxx | 32位的十六進制值為*xxxx*的字符(Unicode only) | (2) |
| \v | ASCII垂直制表(VT) | ? |
| \ooo | 八進制值為*ooo*的字符 | (3,5) |
| \xhh | 十六進制值為*hh*的字符 | (4,5) |
說明:
1. 形成代理對一部分的代碼單元可以使用這種轉義序列編碼。
1. 任何Unicode字符都可以用這種方式編碼,但如果Python 編譯成使用16比特代碼單元(默認行為),位于基本多語言平面(BMP)之外的字符將用代理對編碼。
1. 與標準C 一樣,最多接受三個八進制數字。
1. 與標準C 不同,要求兩個精確的十六進制數字。
1. 在字符串字面值中, 十六進制和八進制轉義字符表示具有給定值的字節;沒有必要再用那個字節編碼源字符集中的字符。在Unicode字面值中,這些轉義字符表示一個具有給定值的Unicode字符。
與標準C 不同, 所有不能識別的轉義序列都會保留留在字符串中維持不變,例如,*反斜杠會保留在字符串串中*。(這個行為在調試的時候特別有用:如果敲錯一個轉義序列,輸出的結果可以很容易看出是有問題的。)同樣要注意,上面表格中標記為“(Unicode only)”的轉義序列,在非Unicode字符串字面值中屬于不能識別的類別。
當出現前綴'r' 或'R'時,緊跟在反斜杠后面的字符會包含在字符串中不變,并且*所有的反斜杠都會保留在字符串中*。例如,字符串字面值r"\n" 由兩個字符組成:一個反斜杠和一個小寫的'n'。字符串的引號可以用反斜杠轉義,但是反斜杠會保留在字符串中;例如,r"\"" 是一個由兩個字符組成的合法的字符串字面值:一個反斜杠和一個雙引號;r"\" 不是一個合法的字符串字面值(即使原始字符串不能以奇數個反斜杠結束)。特別地, *原始字符串不能以一個反斜線結束*(因為反斜杠會轉義隨后的引用字符)。還要注意后面緊跟著換行符的反斜杠被解釋為字符串中的兩個字符,而*不*是作為續行處理。
如果前綴'r' 或者'R' 和前綴'u' or 'U'一起使用,那么轉義序列uXXXX 和UXXXXXXXX 會被處理而*其它所有反斜杠會保留在字符串中*。例如,字符串字面值ur"\u0062\n" 有三個Unicode 字符組成:‘拉丁小寫字母b’、‘反斜杠’和‘拉丁小寫字母n’。反斜杠可以用前面的反斜杠轉義;然而,兩個都會保留在字符串中。結果,轉義序列\uXXXX只有在奇數個反斜杠的時候才能識別。
#### 2.4.2. 字符串字面值的連接
多個相鄰的字符串字面值(由空白分隔),可能使用不同的引用習慣,是允許的且含義是把它們連接起來。因此,"hello"'world'等同于"helloworld" 。這個特性能夠用于減少需要的反斜杠的數目以方便地把很長的字符串分成幾行,或者甚至給字符串的某些部分加上注釋,例如:
~~~
re.compile("[A-Za-z_]" # letter or underscore
"[A-Za-z0-9_]*" # letter, digit or underscore
)
~~~
注意,這個特性在語法層面上定義,但是在編譯的時候實現。‘+’運算符用于連接字符串表達式必須在運行的時候。還需要注意,字面值的連接可以為每個部分使用不同的引號風格(即使是混合原始字符串和三引號字符串)。
#### 2.4.3. 數值字面值
有四種類型的數值字面值:普通整數、長整數、浮點數和虛數。沒有復數字面值(復數字面值可以由一個實數和一個虛數相加形成)。
注意數值字面值不包括符號;像-1這樣的短語實際上是由一元運算符‘-’和字面值1組成的表達式。
#### 2.4.4. 整數和長整數字面值
整數和長整數字面值可以用以下詞法定義描述:
~~~
longinteger ::= integer ("l" | "L")
integer ::= decimalinteger | octinteger | hexinteger | bininteger
decimalinteger ::= nonzerodigit digit* | "0"
octinteger ::= "0" ("o" | "O") octdigit+ | "0" octdigit+
hexinteger ::= "0" ("x" | "X") hexdigit+
bininteger ::= "0" ("b" | "B") bindigit+
nonzerodigit ::= "1"..."9"
octdigit ::= "0"..."7"
bindigit ::= "0" | "1"
hexdigit ::= digit | "a"..."f" | "A"..."F"
~~~
大于最大可表示普通整數的普通整數字面值(例如,2147483647)會被當作長整數。[[1]](#)長整數字面值大小沒有限制,除了可用內存的容量。
一些普通整數字面值(第一行)和長整數字面值(第二行和第三行)的例子:
~~~
7 2147483647 0177
3L 79228162514264337593543950336L 0377L 0x100000000L
79228162514264337593543950336 0xdeadbeef
~~~
#### 2.4.5. 浮點數字面值
浮點數字面值由以下詞法定義描述:
~~~
floatnumber ::= pointfloat | exponentfloat
pointfloat ::= [intpart] fraction | intpart "."
exponentfloat ::= (intpart | pointfloat) exponent
intpart ::= digit+
fraction ::= "." digit+
exponent ::= ("e" | "E") ["+" | "-"] digit+
~~~
注意浮點數的整數部分和指數部分可能看上去像八進制數,但仍然用十進制解釋。例如,077e010是合法的,它和77e10表示同一個數。浮點數字面值允許的范圍依賴于具體的實現。一些浮點數字面值的例子:
~~~
3.14 10. .001 1e100 3.14e-10 0e0
~~~
注意數值字面值不包括符號;像-1這樣的短語實際上是由一元運算符‘-’和字面值1組成的表達式。
#### 2.4.6. 虛數字面值
虛數字面值由以下詞法定義描述:
~~~
imagnumber ::= (floatnumber | intpart) ("j" | "J")
~~~
虛數字面值生成一個實部為0.0 的復數。復數由一對具有相同取值范圍的浮點數表示。若要創建一個實部非零的復數,可以給它相加一個浮點數,例如,(3+4j)。一些虛數字面值的例子:
~~~
3.14j 10.j 10j .001j 1e100j 3.14e-10j
~~~
### 2.5. 操作符
以下詞符是操作符:
~~~
+ - * ** / // %
<< >> & | ^ ~
< > <= >= == != <>
~~~
比較操作符<>和!=是相同操作符的兩個可選的拼寫。推薦使用!=拼寫,<>已經過時。
### 2.6. 分隔符
以下詞符用作文法中的分隔符:
~~~
( ) [ ] { } @
, : . ` = ;
+= -= *= /= //= %=
&= |= ^= >>= <<= **=
~~~
句號也可以出現在浮點數和虛數字面值中。一個連續三個句號的序列在切片中具有省略號這樣特殊的含義。列表的第二部分,即參數化賦值運算符,在詞法上是作為分隔符處理,但也執行運算。
以下可打印ASCII字符作為其它詞符的一部分有著特殊的含義,或者對于詞法分析器具有重要作用:
~~~
' " # \
~~~
以下可打印ASCII字符在Python中沒有使用。它們出現在字符串字面值和注釋之外是無條件的一個錯誤:
~~~
$ ?
~~~
腳注
| [[1]](#) | 在Python 2.4之前的版本中,在最大的可表示普通整數和最大的無符號32位數字4294967296(在一臺使用32位算術的機器上)范圍之間八進制和十六進制字面值會通過減去4294967296作為負的普通整數。 |
|-----|-----|
- Python 2 教程
- 1. 吊吊你的胃口
- 2. Python 解釋器
- 3. Python簡介
- 4. 控制流
- 5. 數據結構
- 6. 模塊
- 7. 輸入和輸出
- 8. 錯誤和異常
- 9. 類
- 10. 標準庫概覽
- 11. 標準庫概覽 — 第II部分
- 12.現在怎么辦?
- 13. 交互式輸入的編輯和歷史記錄
- 14. 浮點數運算:問題和局限
- Python 2 標準庫
- 1. 引言
- 2. 內建函數
- 3. 不太重要的內建函數
- 4. 內建的常量
- 5. 內建的類型
- 6. 內建的異常
- 7. String Services
- 8. Data Types
- 9. Numeric and Mathematical Modules
- 10. File and Directory Access
- 11. Data Persistence
- 13. File Formats
- 14. Cryptographic Services
- 15. Generic Operating System Services
- 16. Optional Operating System Services
- 17. Interprocess Communication and Networking
- 18. Internet Data Handling
- 20. Internet Protocols and Support
- 26. Debugging and Profiling
- 28. Python Runtime Services
- Python 2 語言參考
- 1. 簡介
- 2. 詞法分析
- 3. 數據模型
- 4. 執行模型
- 5. 表達式
- 6. 簡單語句
- 7. 復合語句
- 8. 頂層的組件
- 9. 完整的語法規范
- Python 3 教程
- 1. 引言
- 2. Python 解釋器
- 3. Python簡介
- 4. 控制流
- 5. 數據結構
- 6. 模塊
- 7. 輸入和輸出
- 8. 錯誤和異常
- 9. 類
- 10. 標準庫概覽
- 11. 標準庫概覽 — 第II部分
- 12.現在怎么辦?
- 13. 交互式輸入的編輯和歷史記錄
- 14. 浮點數運算:問題和局限