2. 詞法分析¶
Python 程式由一個*解析器*讀取。 解析器的輸入是由*詞法分析器*(也稱為 *tokenizer* 或*分詞器*)生成的 詞法單元 流。 本章介紹詞法分析器如何生成這些詞法單元。
詞法分析器會確定程式文字的 編碼 (預設為 UTF-8),並將文字解碼為 源字元。 如果文字無法解碼,則會引發 SyntaxError
。
接下來,詞法分析器使用源字元來生成詞法單元流。所生成詞法單元的型別通常取決於下一個要處理的源字元。類似地,分析器的其他特殊行為也取決於尚未處理的第一個源字元。下表快速總結了這些源字元,並提供了指向包含更多資訊章節的連結。
字元 |
下一個詞法單元(或其他相關文件) |
---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2.1. 行結構¶
一個 Python 程式會分為多個*邏輯行*。
2.1.1. 邏輯行¶
邏輯行的結束由詞法單元 NEWLINE
表示。 語句不能跨越邏輯行邊界,除非語法允許 NEWLINE
(例如,在複合語句中的語句之間)。 一個邏輯行由一個或多個 *物理行* 遵循顯式或隱式的*行拼接*規則構成。
2.1.2. 物理行¶
物理行是以以下行尾序列之一結束的字元序列
Unix 形式,使用 ASCII LF (換行符),
Windows 形式,使用 ASCII 序列 CR LF (回車後跟換行符),
“經典 Mac OS”形式,使用 ASCII CR (回車符)。
無論平臺如何,這些序列中的每一個都會被替換為單個 ASCII LF (換行符)。(即使在字串字面值內部也是如此。)每行可以使用任何一種序列;它們在檔案中不必保持一致。
輸入結束也作為最後一個物理行的隱式終止符。
形式上
newline: <ASCII LF> | <ASCII CR> <ASCII LF> | <ASCII CR>
2.1.4. 編碼宣告¶
如果 Python 指令碼的第一行或第二行中的註釋與正則表示式 coding[=:]\s*([-\w.]+)
相匹配,則此註釋將被作為編碼宣告來處理;此表示式的第一個分組將指定原始碼檔案的編碼。編碼宣告必須單獨成行。如果它是在第二行,則第一行也必須是僅包含註釋的行。推薦的編碼表達式形式為
# -*- coding: <encoding-name> -*-
GNU Emacs 也能識別這種形式,以及
# vim:fileencoding=<encoding-name>
Bram Moolenaar 的 VIM 也能識別這種形式。
如果沒有找到編碼宣告,則預設編碼為 UTF-8。如果檔案的隱式或顯式編碼為 UTF-8,則開頭的 UTF-8 位元組順序標記 (b'\xef\xbb\xbf'
) 會被忽略而不是導致語法錯誤。
如果聲明瞭編碼,則編碼名稱必須被 Python 識別(參見標準編碼)。該編碼將用於所有詞法分析,包括字串字面值、註釋和識別符號。
所有詞法分析,包括字串字面值、註釋和識別符號,都在使用源編碼解碼後的 Unicode 文字上進行。除了 NUL 控制字元外,任何 Unicode 碼點都可以出現在 Python 原始碼中。
source_character: <any Unicode code point, except NUL>
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
詞法單元)。在互動式輸入語句期間,空白行的處理可能因讀取-求值-列印迴圈的實現而異。在標準互動式直譯器中,一個完全空白的邏輯行(即甚至不包含空白或註釋的行)會終止一個多行語句。
2.1.8. 縮排¶
邏輯行開頭的行首空白(空格和製表符)用於計算該行的縮排級別,這又被用來確定語句的分組。
製表符會被(從左到右)替換為一到八個空格,以使替換後包括替換在內的總字元數是八的倍數(這旨在與 Unix 使用的規則相同)。然後,第一個非空白字元之前的空格總數決定了該行的縮排。縮排不能使用反斜槓跨越多個物理行;第一個反斜槓之前的空白決定了縮排。
如果原始檔混合使用製表符和空格的方式使得其含義依賴於一個製表符等於多少個空格,則縮排將被視為不一致而被拒絕;在這種情況下會引發 TabError
。
跨平臺相容性說明:由於非 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
(實際上,前三個錯誤由解析器檢測;只有最後一個錯誤由詞法分析器發現 — return r
的縮排與從棧中彈出的級別不匹配。)
2.1.9. 詞法單元之間的空白¶
除了在邏輯行的開頭或字串字面值中,空白字元空格、製表符和換頁符可以互換使用來分隔詞法單元。只有當兩個詞法單元的拼接可能被解釋為另一個不同的詞法單元時,它們之間才需要空白。例如,ab
是一個詞法單元,但 a b
是兩個詞法單元。然而,+a
和 + a
都產生兩個詞法單元,+
和 a
,因為 +a
不是一個有效的詞法單元。
2.1.10. 結束標記¶
在非互動式輸入的末尾,詞法分析器會生成一個 ENDMARKER
詞法單元。
2.2. 其他詞法單元¶
除了 NEWLINE
、INDENT
和 DEDENT
之外,還存在以下幾類詞法單元:*識別符號*和*關鍵字* (NAME
),*字面值*(例如 NUMBER
和 STRING
),以及其他符號(*運算子*和*分隔符*,OP
)。空白字元(除了前面討論過的邏輯行終止符)不是詞法單元,但用於分隔詞法單元。當存在歧義時,一個詞法單元由從左到右讀取時能構成合法詞法單元的最長字串組成。
2.3. 名稱(識別符號和關鍵字)¶
NAME
詞法單元代表*識別符號*、*關鍵字*和*軟關鍵字*。
在 ASCII 範圍(U+0001..U+007F)內,名稱的有效字元包括大寫和小寫字母(A-Z
和 a-z
)、下劃線 _
,以及除了首字元外的數字 0
到 9
。
名稱必須至少包含一個字元,但沒有長度上限。大小寫是敏感的。
除了 A-Z
、a-z
、_
和 0-9
之外,名稱還可以使用 ASCII 範圍之外的“類字母”和“類數字”字元,詳見下文。
所有識別符號在解析時都會被轉換為 規範化形式 NFKC;識別符號的比較基於 NFKC。
形式上,規範化識別符號的首字元必須屬於集合 id_start
,它是以下各項的並集:
Unicode 類別
<Lu>
- 大寫字母(包括A
到Z
)Unicode 類別
<Ll>
- 小寫字母(包括a
到z
)Unicode 類別
<Lt>
- 詞首大寫字母Unicode 類別
<Lm>
- 修飾字母Unicode 類別
<Lo>
- 其他字母Unicode 類別
<Nl>
- 字母數字{
"_"
} - 下劃線<Other_ID_Start>
- 在 PropList.txt 中為了支援向後相容而明確指定的字元集
其餘字元必須屬於集合 id_continue
,它是以下各項的並集:
id_start
中的所有字元Unicode 類別
<Nd>
- 十進位制數字(包括0
到9
)Unicode 類別
<Pc>
- 連線標點Unicode 類別
<Mn>
- 非間距標記Unicode 類別
<Mc>
- 間距組合標記<Other_ID_Continue>
- 在 PropList.txt 中為了支援向後相容而明確指定的另一個字元集
Unicode 類別使用 unicodedata
模組中包含的 Unicode 字元資料庫版本。
這些集合基於 Unicode 標準附件 UAX-31。更多詳情請參閱 PEP 3131。
更形式化地,名稱由以下詞法定義描述:
NAME:xid_start
xid_continue
* id_start: <Lu> | <Ll> | <Lt> | <Lm> | <Lo> | <Nl> | "_" | <Other_ID_Start> id_continue:id_start
| <Nd> | <Pc> | <Mn> | <Mc> | <Other_ID_Continue> xid_start: <all characters inid_start
whose NFKC normalization is in (id_start
xid_continue
*)"> xid_continue: <all characters inid_continue
whose NFKC normalization is in (id_continue
*)"> identifier: <NAME
, except keywords>
Unicode 字元資料庫中的 DerivedCoreProperties.txt 檔案提供了由 Unicode 定義的所有有效識別符號字元的非規範性列表。
2.3.1. 關鍵字¶
以下名稱被用作語言的保留字,或稱*關鍵字*,不能用作普通識別符號。它們必須完全按照此處所示的拼寫使用:
False await else import pass
None break except in raise
True class finally is return
and continue for lambda try
as def from nonlocal while
assert del global not with
async elif if or yield
2.3.2. 軟關鍵字¶
在 3.10 版本加入。
有些名稱僅在特定上下文中被保留。這些被稱為*軟關鍵字*:
這些在它們的特定上下文中語法上表現為關鍵字,但這種區分是在解析器層面進行的,而不是在分詞時。
作為軟關鍵字,它們在語法中的使用是可能的,同時仍然保持與使用這些名稱作為識別符號的現有程式碼的相容性。
在 3.12 版本發生變更: type
現在是一個軟關鍵字。
2.3.3. 保留的識別符號類¶
某些類別的識別符號(除了關鍵字)具有特殊含義。這些類別透過前導和尾隨下劃線字元的模式來識別:
_*
不會被
from module import *
匯入。_
在
match
語句中的case
模式裡,_
是一個軟關鍵字,表示一個萬用字元。另外,互動式直譯器將上一次求值的結果放在變數
_
中。(它與內建函式如print
一起儲存在builtins
模組中。)在其他地方,
_
是一個普通識別符號。它通常用於命名“特殊”項,但對 Python 本身來說並不特殊。__*__
系統定義的名稱,非正式地稱為“dunder”名稱。這些名稱由直譯器及其實現(包括標準庫)定義。當前的系統名稱在特殊方法名稱部分和其他地方討論。未來版本的 Python 可能會定義更多。*任何*在任何上下文中對
__*__
名稱的使用,如果不遵循明確文件化的用法,都可能在沒有警告的情況下被破壞。__*
類私有名稱。當在類定義上下文中使用時,此類別中的名稱會被重寫以使用一種變形形式,以幫助避免基類和派生類的“私有”屬性之間的名稱衝突。請參見識別符號(名稱)部分。
2.4. 字面值¶
字面值是某些內建型別常量值的表示法。
2.5. 字串和位元組串字面值¶
字串字面值是用單引號 ('
) 或雙引號 ("
) 括起來的文字。例如:
"spam"
'eggs'
用於開始字面值的引號也用於結束它,因此字串字面值只能包含另一種引號(除非使用轉義序列,見下文)。例如:
'Say "Hello", please.'
"Don't do that!"
除了這個限制,引號字元('
或 "
)的選擇不會影響字面值的解析方式。
在字串字面值內部,反斜槓(\
)字元引入一個*轉義序列*,它根據反斜槓後的字元具有特殊含義。例如,\"
表示雙引號字元,並且*不*會結束字串:
>>> print("Say \"Hello\" to everyone!")
Say "Hello" to everyone!
有關此類序列的完整列表和更多詳細資訊,請參見下文的轉義序列。
2.5.1. 三引號字串¶
字串也可以用匹配的三組單引號或雙引號括起來。這些通常被稱為*三引號字串*:
"""This is a triple-quoted string."""
在三引號字面值中,允許使用未轉義的引號(並且會保留),但連續三個未轉義的引號會終止字面值,如果它們與開始時使用的引號型別相同('
或 "
):
"""This string has "quotes" inside."""
未轉義的換行符也是允許的並會被保留:
'''This triple-quoted string
continues on the next line.'''
2.5.2. 字串字首¶
字串字面值可以有一個可選的*字首*,它會影響字面值內容的解析方式,例如:
b"data"
f'{result=}'
允許的字首有:
有關每種型別的詳細資訊,請參閱連結的部分。
字首不區分大小寫(例如,‘B
’ 的作用與 ‘b
’ 相同)。‘r
’ 字首可以與 ‘f
’、‘t
’ 或 ‘b
’ 組合,因此 ‘fr
’、‘rf
’、‘tr
’、‘rt
’、‘br
’ 和 ‘rb
’ 也是有效的字首。
在 3.3 版本加入: 添加了原始位元組串字面值的 'rb'
字首作為 'br'
的同義詞。
為了簡化維護 Python 2.x 和 3.x 雙程式碼庫,重新引入了對 unicode 遺留字面值(u'value'
)的支援。更多資訊請參閱 PEP 414。
2.5.3. 形式語法¶
除了“f-字串”和“t-字串”,字串字面值由以下詞法定義描述。
這些定義使用負向先行斷言(!
)來表示結束引號會終止字面值。
STRING: [stringprefix
] (stringcontent
) stringprefix: <("r" | "u" | "b" | "br" | "rb"), case-insensitive> stringcontent: | "'''" ( !"'''"longstringitem
)* "'''" | '"""' ( !'"""'longstringitem
)* '"""' | "'" ( !"'"stringitem
)* "'" | '"' ( !'"'stringitem
)* '"' stringitem:stringchar
|stringescapeseq
stringchar: <anysource_character
, except backslash and newline> longstringitem:stringitem
| newline stringescapeseq: "\" <anysource_character
>
請注意,與所有詞法定義一樣,空白是重要的。特別是,字首(如果有)必須緊跟在起始引號之後。
2.5.4. 轉義序列¶
除非存在 ‘r
’ 或 ‘R
’ 字首,否則字串和位元組串字面值中的轉義序列將根據與標準 C 類似的規則進行解釋。可識別的轉義序列是:
轉義序列 |
含義 |
---|---|
|
|
|
|
|
|
|
|
|
ASCII 響鈴 (BEL) |
|
ASCII 退格 (BS) |
|
ASCII 換頁 (FF) |
|
ASCII 換行 (LF) |
|
ASCII 回車 (CR) |
|
ASCII 水平製表符 (TAB) |
|
ASCII 垂直製表符 (VT) |
|
|
|
|
|
|
|
|
|
2.5.4.1. 被忽略的行尾¶
可以在行尾新增反斜槓以忽略換行符:
>>> 'This string will not include \
... backslashes or newline characters.'
'This string will not include backslashes or newline characters.'
2.5.4.2. 跳脫字元¶
要在非原始 Python 字串字面值中包含反斜槓,必須將其加倍。 \\
轉義序列表示單個反斜槓字元:
>>> print('C:\\Program Files')
C:\Program Files
類似地,\'
和 \"
序列分別表示單引號和雙引號字元:
>>> print('\' and \"')
' and "
2.5.4.3. 八進位制字元¶
序列 \ooo
表示一個八進位制(基數為 8)值為 ooo 的*字元*:
>>> '\120'
'P'
最多接受三位八進位制數字(0 到 7)。
在位元組串字面值中,*字元*意味著一個具有給定值的*位元組*。在字串字面值中,它意味著一個具有給定值的 Unicode 字元。
在 3.11 版本發生變更: 值大於 0o377
(255) 的八進位制轉義會產生一個 DeprecationWarning
。
在 3.12 版本發生變更: 值大於 0o377
(255) 的八進位制轉義會產生一個 SyntaxWarning
。在未來的 Python 版本中,它們將引發一個 SyntaxError
。
2.5.4.4. 十六進位制字元¶
序列 \xhh
表示一個十六進位制(基數為 16)值為 hh 的*字元*:
>>> '\x50'
'P'
與標準 C 不同,這裡要求必須是兩個十六進位制數字。
在位元組串字面值中,*字元*意味著一個具有給定值的*位元組*。在字串字面值中,它意味著一個具有給定值的 Unicode 字元。
2.5.4.5. 具名 Unicode 字元¶
序列 \N{name}
表示一個具有給定*名稱*的 Unicode 字元:
>>> '\N{LATIN CAPITAL LETTER P}'
'P'
>>> '\N{SNAKE}'
'🐍'
此序列不能出現在位元組串字面值中。
在 3.3 版本發生變更: 已新增對名稱別名的支援。
2.5.4.6. 十六進位制 Unicode 字元¶
序列 \uxxxx
和 \Uxxxxxxxx
表示具有給定十六進位制(基數為 16)值的 Unicode 字元。\u
要求正好四個數字;\U
要求正好八個數字。後者可以編碼任何 Unicode 字元。
>>> '\u1234'
'ሴ'
>>> '\U0001f40d'
'🐍'
這些序列不能出現在位元組串字面值中。
2.5.4.7. 未識別的轉義序列¶
與標準 C 不同,所有未識別的轉義序列都會在字串中保持不變,也就是說,*反斜槓會保留在結果中*:
>>> print('\q')
\q
>>> list('\q')
['\\', 'q']
請注意,對於位元組串字面值,僅在字串字面值中識別的轉義序列(\N...
、\u...
、\U...
)屬於未識別的轉義類別。
在 3.6 版本發生變更: 未識別的轉義序列會產生一個 DeprecationWarning
。
在 3.12 版本發生變更: 未識別的轉義序列會產生一個 SyntaxWarning
。在未來的 Python 版本中,它們將引發一個 SyntaxError
。
2.5.5. 位元組串字面值¶
*位元組串字面值*總是以 ‘b
’ 或 ‘B
’ 為字首;它們產生 bytes
型別的例項,而不是 str
型別。它們只能包含 ASCII 字元;數值為 128 或更大的位元組必須用轉義序列表示(通常是十六進位制字元或八進位制字元):
>>> b'\x89PNG\r\n\x1a\n'
b'\x89PNG\r\n\x1a\n'
>>> list(b'\x89PNG\r\n\x1a\n')
[137, 80, 78, 71, 13, 10, 26, 10]
類似地,零位元組必須使用轉義序列(通常是 \0
或 \x00
)來表示。
2.5.6. 原始字串字面值¶
字串和位元組串字面值都可以選擇性地以字母 ‘r
’ 或 ‘R
’ 為字首;這樣的構造分別稱為*原始字串字面值*和*原始位元組串字面值*,它們將反斜槓視為字面字元。因此,在原始字串字面值中,轉義序列不會被特殊處理:
>>> r'\d{4}-\d{2}-\d{2}'
'\\d{4}-\\d{2}-\\d{2}'
即使在原始字面值中,引號也可以用反斜槓轉義,但反斜槓會保留在結果中;例如,r"\""
是一個有效的字串字面值,由兩個字元組成:一個反斜槓和一個雙引號;r"\"
不是一個有效的字串字面值(即使是原始字串也不能以奇數個反斜槓結尾)。具體來說,*原始字面值不能以單個反斜槓結尾*(因為反斜槓會轉義後面的引號字元)。還要注意,單個反斜槓後跟一個換行符會被解釋為字面值中的這兩個字元,*而不會*被視為行延續。
2.5.7. f-字串¶
在 3.6 版本加入。
一個*格式化字串字面值*或 *f-字串* 是以 ‘f
’ 或 ‘F
’ 為字首的字串字面值。這些字串可以包含由花括號 {}
分隔的替換欄位,這些欄位是表示式。雖然其他字串字面值總是有常量值,但格式化字串實際上是在執行時求值的表示式。
轉義序列的解碼方式與普通字串字面值相同(除非字面值也標記為原始字串)。解碼後,字串內容的語法為:
f_string: (literal_char
| "{{" | "}}" |replacement_field
)* replacement_field: "{"f_expression
["="] ["!"conversion
] [":"format_spec
] "}" f_expression: (conditional_expression
| "*"or_expr
) (","conditional_expression
| "," "*"or_expr
)* [","] |yield_expression
conversion: "s" | "r" | "a" format_spec: (literal_char
|replacement_field
)* literal_char: <any code point except "{", "}" or NULL>
字串中花括號之外的部分按字面處理,但任何雙花括號 '{{'
或 '}}'
都會被替換為相應的單個花括號。單個左花括號 '{'
標記一個替換欄位,它以一個 Python 表示式開始。為了同時顯示錶達式文字及其求值後的值(在除錯時很有用),可以在表示式後新增一個等號 '='
。後面可以跟一個由感嘆號 '!'
引入的轉換欄位。還可以附加一個由冒號 ':'
引入的格式說明符。替換欄位以一個右花括號 '}'
結束。
格式化字串字面值中的表示式被視為由圓括號包圍的常規 Python 表示式,但有幾個例外。不允許空表示式,lambda
和賦值表示式 :=
必須用顯式圓括號包圍。每個表示式都在格式化字串字面值出現的上下文中從左到右求值。替換表示式可以在單引號和三引號 f-字串中包含換行符,並且它們可以包含註釋。在替換欄位中 #
之後的所有內容都是註釋(即使是右括號和引號)。在這種情況下,替換欄位必須在不同的行中關閉。
>>> f"abc{a # This is a comment }"
... + 3}"
'abc5'
在 3.12 版本發生變更: 在 Python 3.12 之前,f-字串替換欄位內不允許有註釋。
當提供等號 '='
時,輸出將包含表示式文字、'='
和求值後的值。左花括號 '{'
之後、表示式內部以及 '='
之後的所有空格都會保留在輸出中。預設情況下,'='
會提供表示式的 repr()
,除非指定了格式。當指定了格式時,它預設為表示式的 str()
,除非聲明瞭 '!r'
轉換。
在 3.8 版本加入: 等號 '='
。
如果指定了轉換,表示式求值的結果會在格式化之前被轉換。轉換 '!s'
對結果呼叫 str()
,'!r'
呼叫 repr()
,而 '!a'
呼叫 ascii()
。
然後使用 format()
協議對結果進行格式化。格式說明符會傳遞給表示式或轉換結果的 __format__()
方法。如果省略格式說明符,則傳遞一個空字串。格式化的結果隨後被包含在整個字串的最終值中。
頂層格式說明符可以包含巢狀的替換欄位。這些巢狀欄位可以包含它們自己的轉換欄位和格式說明符,但不能包含更深層巢狀的替換欄位。格式說明符迷你語言與 str.format()
方法使用的相同。
格式化字串字面值可以被拼接,但替換欄位不能跨越字面值進行分割。
一些格式化字串字面值的示例:
>>> name = "Fred"
>>> f"He said his name is {name!r}."
"He said his name is 'Fred'."
>>> f"He said his name is {repr(name)}." # repr() is equivalent to !r
"He said his name is 'Fred'."
>>> width = 10
>>> precision = 4
>>> value = decimal.Decimal("12.34567")
>>> f"result: {value:{width}.{precision}}" # nested fields
'result: 12.35'
>>> today = datetime(year=2017, month=1, day=27)
>>> f"{today:%B %d, %Y}" # using date format specifier
'January 27, 2017'
>>> f"{today=:%B %d, %Y}" # using date format specifier and debugging
'today=January 27, 2017'
>>> number = 1024
>>> f"{number:#0x}" # using integer format specifier
'0x400'
>>> foo = "bar"
>>> f"{ foo = }" # preserves whitespace
" foo = 'bar'"
>>> line = "The mill's closed"
>>> f"{line = }"
'line = "The mill\'s closed"'
>>> f"{line = :20}"
"line = The mill's closed "
>>> f"{line = !r:20}"
'line = "The mill\'s closed" '
在替換欄位內重用外部 f-字串的引號型別是允許的:
>>> a = dict(x=2)
>>> f"abc {a["x"]} def"
'abc 2 def'
在 3.12 版本發生變更: 在 Python 3.12 之前,在替換欄位內重用外部 f-字串的相同引號型別是不可能的。
反斜槓也允許在替換欄位中使用,並且其求值方式與在任何其他上下文中相同:
>>> a = ["a", "b", "c"]
>>> print(f"List a contains:\n{"\n".join(a)}")
List a contains:
a
b
c
在 3.12 版本發生變更: 在 Python 3.12 之前,f-字串替換欄位內不允許有反斜槓。
格式化字串字面值不能用作文件字串,即使它們不包含表示式。
>>> def foo():
... f"Not a docstring"
...
>>> foo.__doc__ is None
True
另請參閱 PEP 498(添加了格式化字串字面值的提案),以及 str.format()
,它使用了一種相關的格式化字串機制。
2.5.8. t-字串¶
在 3.14 版本加入。
一個*模板字串字面值*或*t-字串*是以 ‘t
’ 或 ‘T
’ 為字首的字串字面值。這些字串遵循與格式化字串字面值相同的語法和求值規則,但有以下區別:
模板字串字面值求值後得到一個
string.templatelib.Template
物件,而不是一個str
物件。不使用
format()
協議。相反,格式說明符和轉換(如果有)會傳遞給為每個求值表示式建立的一個新的Interpolation
物件。由處理生成的Template
物件的程式碼來決定如何處理格式說明符和轉換。包含巢狀替換欄位的格式說明符會先被急切求值,然後再傳遞給
Interpolation
物件。例如,一個形式為{amount:.{precision}f}
的插值會先求值內部表示式{precision}
以確定format_spec
屬性的值。如果precision
為2
,那麼生成的格式說明符將是'.2f'
。當在插值表示式中提供等號
'='
時,表示式的文字會附加到相關插值之前的字面字串中。這包括等號和任何周圍的空白。表示式的Interpolation
例項將正常建立,只是conversion
將預設設定為 ‘r
’ (repr()
)。如果提供了顯式的轉換或格式說明符,則會覆蓋預設行為。
2.6. 數字字面值¶
NUMBER
詞法單元代表數字字面值,共有三種類型:整數、浮點數和虛數。
NUMBER:integer
|floatnumber
|imagnumber
數字字面值的數值與其作為字串傳遞給 int
、float
或 complex
類建構函式的數值相同。請注意,並非所有這些建構函式的有效輸入也都是有效的字面值。
數字字面值不包括符號;像 -1
這樣的短語實際上是由一元運算子 ‘-
’ 和字面值 1
組成的表示式。
2.6.1. 整數字面值¶
整數字面值表示整數。例如:
7
3
2147483647
整數字面值的長度沒有限制,除了可用記憶體所能儲存的範圍:
7922816251426433759354395033679228162514264337593543950336
下劃線可用於對數字進行分組以增強可讀性,並且在確定字面值的數值時會被忽略。例如,以下字面值是等效的:
100_000_000_000
100000000000
1_00_00_00_00_000
下劃線只能出現在數字之間。例如,_123
、321_
和 123__321
都*不是*有效的字面值。
整數可以分別使用字首 0b
、0o
和 0x
指定為二進位制(基數 2)、八進位制(基數 8)或十六進位制(基數 16)。十六進位制數字 10 到 15 由字母 A
-F
表示,不區分大小寫。例如:
0b100110111
0b_1110_0101
0o177
0o377
0xdeadbeef
0xDead_Beef
下劃線可以跟在進位制說明符之後。例如,0x_1f
是一個有效的字面值,但 0_x1f
和 0x__1f
不是。
非零十進位制數中不允許有前導零。例如,0123
不是一個有效的字面值。這是為了與 C 風格的八進位制字面值進行區分,Python 在 3.0 版本之前使用這種風格。
形式上,整數字面值由以下詞法定義描述:
integer:decinteger
|bininteger
|octinteger
|hexinteger
|zerointeger
decinteger:nonzerodigit
(["_"]digit
)* bininteger: "0" ("b" | "B") (["_"]bindigit
)+ octinteger: "0" ("o" | "O") (["_"]octdigit
)+ hexinteger: "0" ("x" | "X") (["_"]hexdigit
)+ zerointeger: "0"+ (["_"] "0")* nonzerodigit: "1"..."9" digit: "0"..."9" bindigit: "0" | "1" octdigit: "0"..."7" hexdigit:digit
| "a"..."f" | "A"..."F"
在 3.6 版本發生變更: 現在允許在字面值中使用下劃線進行分組。
2.6.2. 浮點數字面值¶
浮點(float)字面值,如 3.14
或 1.5
,表示實數的近似值。
它們由*整數*部分和*小數*部分組成,每個部分都由十進位制數字構成。這兩個部分由小數點 .
分隔。
2.71828
4.0
與整數字面值不同,允許有前導零。例如,077.010
是合法的,並且表示與 77.01
相同的數字。
與整數字面值一樣,單個下劃線可以出現在數字之間以幫助提高可讀性:
96_485.332_123
3.14_15_93
這兩個部分中的任何一個都可以為空,但不能同時為空。例如:
10. # (equivalent to 10.0)
.001 # (equivalent to 0.001)
可選地,整數和分數部分後面可以跟一個*指數*:字母 e
或 E
,後跟一個可選的符號 +
或 -
,以及一個與整數和分數部分格式相同的數字。e
或 E
表示“乘以十的……次方”:
1.0e3 # (represents 1.0×10³, or 1000.0)
1.166e-5 # (represents 1.166×10⁻⁵, or 0.00001166)
6.02214076e+23 # (represents 6.02214076×10²³, or 602214076000000000000000.)
在只有整數和指數部分的浮點數中,小數點可以省略:
1e3 # (equivalent to 1.e3 and 1.0e3)
0e0 # (equivalent to 0.)
形式上,浮點字面值由以下詞法定義描述:
floatnumber: |digitpart
"." [digitpart
] [exponent
] | "."digitpart
[exponent
] |digitpart
exponent
digitpart:digit
(["_"]digit
)* exponent: ("e" | "E") ["+" | "-"]digitpart
在 3.6 版本發生變更: 現在允許在字面值中使用下劃線進行分組。
2.6.3. 虛數字面值¶
Python 有複數物件,但沒有複數字面值。相反,*虛數字面值*表示實部為零的複數。
例如,在數學中,複數 3+4.2i 寫為實數 3 加上虛數 4.2i。Python 使用類似的語法,只是虛數單位寫為 j
而不是 i:
3+4.2j
這是一個由整數字面值 3
、運算子 ‘+
’ 和虛數字面值 4.2j
組成的表示式。由於這是三個獨立的詞法單元,它們之間允許有空格:
3 + 4.2j
每個詞法單元*內部*不允許有空格。特別是,j
字尾不能與它前面的數字分開。
j
前面的數字與浮點數字面值具有相同的語法。因此,以下是有效的虛數字面值:
4.2j
3.14j
10.j
.001j
1e100j
3.14e-10j
3.14_15_93j
與浮點數字面值不同,如果虛數只有整數部分,小數點可以省略。該數字仍然被評估為浮點數,而不是整數:
10j
0j
1000000000000000000000000j # equivalent to 1e+24j
j
字尾不區分大小寫。這意味著你可以使用 J
來代替:
3.14J # equivalent to 3.14j
形式上,虛數字面值由以下詞法定義描述:
imagnumber: (floatnumber
|digitpart
) ("j" | "J")
2.7. 運算子和分隔符¶
以下語法定義了*運算子*和*分隔符*詞法單元,即通用的 OP
詞法單元型別。在 token
模組文件中也提供了這些詞法單元及其名稱的列表。
OP: | assignment_operator | bitwise_operator | comparison_operator | enclosing_delimiter | other_delimiter | arithmetic_operator | "..." | other_op assignment_operator: "+=" | "-=" | "*=" | "**=" | "/=" | "//=" | "%=" | "&=" | "|=" | "^=" | "<<=" | ">>=" | "@=" | ":=" bitwise_operator: "&" | "|" | "^" | "~" | "<<" | ">>" comparison_operator: "<=" | ">=" | "<" | ">" | "==" | "!=" enclosing_delimiter: "(" | ")" | "[" | "]" | "{" | "}" other_delimiter: "," | ":" | "!" | ";" | "=" | "->" arithmetic_operator: "+" | "-" | "**" | "*" | "//" | "/" | "%" other_op: "." | "@"
備註
通常,*運算子*用於組合表示式,而*分隔符*用於其他目的。然而,這兩個類別之間沒有明確、正式的區別。
一些詞法單元可以根據用法既作為運算子又作為分隔符。例如,*
既是乘法運算子,也是用於序列解包的分隔符;@
既是矩陣乘法運算子,也是引入裝飾器的分隔符。
對於某些詞法單元,區別並不清楚。例如,有些人認為 .
、(
和 )
是分隔符,而另一些人則將其視為 getattr()
運算子和函式呼叫運算子。
Python 的一些運算子,如 and
、or
和 not in
,使用關鍵字詞法單元而不是“符號”(運算子詞法單元)。
三個連續句點(...
)的序列作為 Ellipsis
字面值具有特殊含義。
2.1.3. 註釋¶
註釋以井號字元(
#
)開始,該字元不是字串字面值的一部分,並結束於物理行的末尾。除非呼叫了隱式行拼接規則,否則註釋表示邏輯行的結束。註釋會被語法忽略。