2. 詞法分析?

Python 程序由 解析器 讀取,輸入解析器的是 詞法分析器 生成的 形符 流。本章介紹詞法分析器怎樣把文件拆成形符。

Python 將讀取的程序文本轉為 Unicode 代碼點(diǎn);編碼聲明用于指定源文件的編碼,默認為 UTF-8,詳見(jiàn) PEP 3120。源文件不能解碼時(shí),觸發(fā) SyntaxError。

2.1. 行結構?

Python 程序可以拆分為多個(gè) 邏輯行。

2.1.1. 邏輯行?

NEWLINE 形符表示結束邏輯行。語(yǔ)句不能超出邏輯行的邊界,除非句法支持 NEWLINE (例如,復合語(yǔ)句中的多行子語(yǔ)句)。根據顯式或隱式 行拼接 規則,一個(gè)或多個(gè) 物理行 可組成邏輯行。

2.1.2. 物理行?

物理行是一序列字符,由行尾序列終止。源文件和字符串可使用任意標準平臺行終止序列 - Unix ASCII 字符 LF (換行)、 Windows ASCII 字符序列 CR LF (回車(chē)換行)、或老式 Macintosh ASCII 字符 CR (回車(chē))。不管在哪個(gè)平臺,這些形式均可等價(jià)使用。輸入結束也可以用作最終物理行的隱式終止符。

嵌入 Python 時(shí),傳入 Python API 的源碼字符串應使用 C 標準慣例換行符(\n,代表 ASCII 字符 LF, 行終止符)。

2.1.3. 注釋?

注釋以井號 (#) 開(kāi)頭,在物理行末尾截止。注意,井號不是字符串字面值。除非應用隱式行拼接規則,否則,注釋代表邏輯行結束。句法不解析注釋。

2.1.4. 編碼聲明?

Python 腳本第一或第二行的注釋匹配正則表達式 coding[=:]\s*([-\w.]+) 時(shí),該注釋會(huì )被當作編碼聲明;這個(gè)表達式的第一組指定了源碼文件的編碼。編碼聲明必須獨占一行,在第二行時(shí),則第一行必須也是注釋。編碼表達式的形式如下:

# -*- coding: <encoding-name> -*-

這也是 GNU Emacs 認可的形式,此外,還支持如下形式:

# vim:fileencoding=<encoding-name>

這是 Bram Moolenaar 的 VIM 認可的形式。

沒(méi)有編碼聲明時(shí),默認編碼為 UTF-8。此外,如果文件的首字節為 UTF-8 字節順序標志(b'\xef\xbb\xbf'),文件編碼也聲明為 UTF-8(這是 Microsoft 的 notepad 等軟件支持的形式)。

If an encoding is declared, the encoding name must be recognized by Python (see 標準編碼). The encoding is used for all lexical analysis, including string literals, comments and identifiers.

2.1.5. 顯式拼接行?

兩個(gè)及兩個(gè)以上的物理行可用反斜杠(\)拼接為一個(gè)邏輯行,規則如下:以不在字符串或注釋內的反斜杠結尾時(shí),物理行將與下一行拼接成一個(gè)邏輯行,并刪除反斜杠及其后的換行符。例如:

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

以反斜杠結尾的行,不能加注釋?zhuān)环葱备芤膊荒芷唇幼⑨?。除字符串字面值外,反斜杠不能拼接形符(如,除字符串字面值外,不能用反斜杠把形符切分至兩個(gè)物理行)。反斜杠只能在代碼的字符串字面值里,在其他任何位置都是非法的。

2.1.6. 隱式拼接行?

圓括號、方括號、花括號內的表達式可以分成多個(gè)物理行,不必使用反斜杠。例如:

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

隱式行拼接可含注釋?zhuān)缓罄m行的縮進(jìn)并不重要;還支持空的后續行。隱式拼接行之間沒(méi)有 NEWLINE 形符。三引號字符串支持隱式拼接行(見(jiàn)下文),但不支持注釋。

2.1.7. 空白行?

只包含空格符、制表符、換頁(yè)符、注釋的邏輯行會(huì )被忽略(即不生成 NEWLINE 形符)。交互模式輸入語(yǔ)句時(shí),空白行的處理方式可能因讀取 - 求值 - 打印循環(huán)(REPL)的具體實(shí)現方式而不同。標準交互模式解釋器中,完全空白的邏輯行(即連空格或注釋都沒(méi)有)將結束多行復合語(yǔ)句。

2.1.8. 縮進(jìn)?

邏輯行開(kāi)頭的空白符(空格符和制表符)用于計算該行的縮進(jìn)層級,決定語(yǔ)句組塊。

制表符(從左至右)被替換為一至八個(gè)空格,縮進(jìn)空格的總數是八的倍數(與 Unix 的規則保持一致)。首個(gè)非空字符前的空格數決定了該行的縮進(jìn)層次??s進(jìn)不能用反斜杠進(jìn)行多行拼接;首個(gè)反斜杠之前的空白符決定了縮進(jìn)的層次。

源文件混用制表符和空格符縮進(jìn)時(shí),因空格數量與制表符相關(guān),由此產(chǎn)生的不一致將導致不能正常識別縮進(jìn)層次,從而觸發(fā) TabError。

跨平臺兼容性說(shuō)明: 鑒于非 UNIX 平臺文本編輯器本身的特性,請勿在源文件中混用制表符和空格符。另外也請注意,不同平臺有可能會(huì )顯式限制最大縮進(jìn)層級。

行首含換頁(yè)符時(shí),縮進(jìn)計算將忽略該換頁(yè)符。換頁(yè)符在行首空白符內其他位置的效果未定義(例如,可能導致空格計數重置為零)。

連續行的縮進(jìn)層級以堆棧形式生成 INDENT 和 DEDENT 形符,說(shuō)明如下。

讀取文件第一行前,先向棧推入一個(gè)零值,該零值不會(huì )被移除。推入棧的層級值從底至頂持續增加。每個(gè)邏輯行開(kāi)頭的行縮進(jìn)層級將與棧頂行比較。如果相等,則不做處理。如果新行層級較高,則會(huì )被推入棧頂,并生成一個(gè) INDENT 形符。如果新行層級較低,則 應當 是棧中的層級數值之一;棧中高于該層級的所有數值都將被移除,每移除一級數值生成一個(gè) DEDENT 形符。文件末尾,棧中剩余的每個(gè)大于零的數值生成一個(gè) DEDENT 形符。

下面的 Python 代碼縮進(jìn)示例雖然正確,但含混不清:

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

下例展示了多種縮進(jìn)錯誤:

 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

(實(shí)際上,解析器可以識別前三個(gè)錯誤;只有最后一個(gè)錯誤由詞法分析器識別 --- return r 的縮進(jìn)無(wú)法匹配從棧里移除的縮進(jìn)層級。)

2.1.9. 形符間的空白字符?

除非在邏輯行開(kāi)頭或字符串內,空格符、制表符、換頁(yè)符等空白符都可以分隔形符。要把兩個(gè)相連形符解讀為不同形符,需要用空白符分隔(例如,ab 是一個(gè)形符,a b 則是兩個(gè)形符)。

2.2. 其他形符?

除 NEWLINE、INDENT、DEDENT 外,還有 標識符、關(guān)鍵字、字面值、運算符 、分隔符 等形符。 空白符(前述的行終止符除外)不是形符,可用于分隔形符。存在二義性時(shí),將從左至右,讀取盡量長(cháng)的字符串組成合法形符。

2.3. 標識符和關(guān)鍵字?

標識符(也稱(chēng)為 名稱(chēng))的詞法定義說(shuō)明如下。

Python 標識符的句法基于 Unicode 標準附件 UAX-31,并加入了下文定義的細化與修改;詳見(jiàn) PEP 3131 。

與 Python 2.x 一樣,在 ASCII 范圍內(U+0001..U+007F),有效標識符字符為: 大小寫(xiě)字母 AZ、下劃線(xiàn) _ 、數字 09,但不能以數字開(kāi)頭。

Python 3.0 引入了 ASCII 之外的更多字符(請參閱 PEP 3131)。這些字符的分類(lèi)使用 unicodedata 模塊中的 Unicode 字符數據庫版本。

標識符的長(cháng)度沒(méi)有限制,但區分大小寫(xiě)。

identifier   ::=  xid_start xid_continue*
id_start     ::=  <all characters in general categories Lu, Ll, Lt, Lm, Lo, Nl, the underscore, and characters with the Other_ID_Start property>
id_continue  ::=  <all characters in id_start, plus characters in the categories Mn, Mc, Nd, Pc and others with the Other_ID_Continue property>
xid_start    ::=  <all characters in id_start whose NFKC normalization is in "id_start xid_continue*">
xid_continue ::=  <all characters in id_continue whose NFKC normalization is in "id_continue*">

上述 Unicode 類(lèi)別碼的含義:

  • Lu - 大寫(xiě)字母

  • Ll - 小寫(xiě)字母

  • Lt - 詞首大寫(xiě)字母

  • Lm - 修飾符字母

  • Lo - 其他字母

  • Nl - 字母數字

  • Mn - 非空白標識

  • Mc - 含空白標識

  • Nd - 十進(jìn)制數字

  • Pc - 連接標點(diǎn)

  • Other_ID_Start - explicit list of characters in PropList.txt to support backwards compatibility

  • Other_ID_Continue - 同上

在解析時(shí),所有標識符都會(huì )被轉換為規范形式 NFKC;標識符的比較都是基于 NFKC。

A non-normative HTML file listing all valid identifier characters for Unicode 14.0.0 can be found at https://www.unicode.org/Public/14.0.0/ucd/DerivedCoreProperties.txt

2.3.1. 關(guān)鍵字?

以下標識符為保留字,或稱(chēng) 關(guān)鍵字,不可用于普通標識符。關(guān)鍵字的拼寫(xiě)必須與這里列出的完全一致:

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. 軟關(guān)鍵字?

3.10 新版功能.

某些標識符僅在特定上下文中被保留。 它們被稱(chēng)為 軟關(guān)鍵字。 match, case_ 等標識符在模式匹配語(yǔ)句相關(guān)的上下文中具有相當于關(guān)鍵字的語(yǔ)義,但這種區分是在解析器層級完成,而不是在形符化的時(shí)候。

作為軟關(guān)鍵字,它們能夠與模式匹配一起使用,同時(shí)仍然保持與使用 match, case_ 作為標識符名稱(chēng)的現有代碼的兼容性。

2.3.3. 保留的標識符類(lèi)?

某些標識符類(lèi)(除了關(guān)鍵字)具有特殊含義。這些類(lèi)的命名模式以下劃線(xiàn)字符開(kāi)頭,并以下劃線(xiàn)結尾:

_*

Not imported by from module import *.

_

In a case pattern within a match statement, _ is a soft keyword that denotes a wildcard.

Separately, the interactive interpreter makes the result of the last evaluation available in the variable _. (It is stored in the builtins module, alongside built-in functions like print.)

Elsewhere, _ is a regular identifier. It is often used to name "special" items, but it is not special to Python itself.

備注

_ 常用于連接國際化文本;詳見(jiàn) gettext 模塊文檔。

It is also commonly used for unused variables.

__*__

系統定義的名稱(chēng),通常簡(jiǎn)稱(chēng)為 "dunder" 。這些名稱(chēng)由解釋器及其實(shí)現(包括標準庫)定義?,F有系統定義名稱(chēng)相關(guān)的論述詳見(jiàn) 特殊方法名稱(chēng) 等章節。Python 未來(lái)版本中還將定義更多此類(lèi)名稱(chēng)。任何情況下,任何 不顯式遵從 __*__ 名稱(chēng)的文檔用法,都可能導致無(wú)警告提示的錯誤。

__*

類(lèi)的私有名稱(chēng)。類(lèi)定義時(shí),此類(lèi)名稱(chēng)以一種混合形式重寫(xiě),以避免基類(lèi)及派生類(lèi)的 "私有" 屬性之間產(chǎn)生名稱(chēng)沖突。詳見(jiàn) 標識符(名稱(chēng))。

2.4. 字面值?

字面值是內置類(lèi)型常量值的表示法。

2.4.1. 字符串與字節串字面值?

字符串字面值的詞法定義如下:

stringliteral   ::=  [stringprefix](shortstring | longstring)
stringprefix    ::=  "r" | "u" | "R" | "U" | "f" | "F"
                     | "fr" | "Fr" | "fR" | "FR" | "rf" | "rF" | "Rf" | "RF"
shortstring     ::=  "'" shortstringitem* "'" | '"' shortstringitem* '"'
longstring      ::=  "'''" longstringitem* "'''" | '"""' longstringitem* '"""'
shortstringitem ::=  shortstringchar | stringescapeseq
longstringitem  ::=  longstringchar | stringescapeseq
shortstringchar ::=  <any source character except "\" or newline or the quote>
longstringchar  ::=  <any source character except "\">
stringescapeseq ::=  "\" <any source character>
bytesliteral   ::=  bytesprefix(shortbytes | longbytes)
bytesprefix    ::=  "b" | "B" | "br" | "Br" | "bR" | "BR" | "rb" | "rB" | "Rb" | "RB"
shortbytes     ::=  "'" shortbytesitem* "'" | '"' shortbytesitem* '"'
longbytes      ::=  "'''" longbytesitem* "'''" | '"""' longbytesitem* '"""'
shortbytesitem ::=  shortbyteschar | bytesescapeseq
longbytesitem  ::=  longbyteschar | bytesescapeseq
shortbyteschar ::=  <any ASCII character except "\" or newline or the quote>
longbyteschar  ::=  <any ASCII character except "\">
bytesescapeseq ::=  "\" <any ASCII character>

One syntactic restriction not indicated by these productions is that whitespace is not allowed between the stringprefix or bytesprefix and the rest of the literal. The source character set is defined by the encoding declaration; it is UTF-8 if no encoding declaration is given in the source file; see section 編碼聲明.

In plain English: Both types of literals can be enclosed in matching single quotes (') or double quotes ("). They can also be enclosed in matching groups of three single or double quotes (these are generally referred to as triple-quoted strings). The backslash (\) character is used to give special meaning to otherwise ordinary characters like n, which means 'newline' when escaped (\n). It can also be used to escape characters that otherwise have a special meaning, such as newline, backslash itself, or the quote character. See escape sequences below for examples.

字節串字面值要加前綴 'b''B';生成的是類(lèi)型 bytes 的實(shí)例,不是類(lèi)型 str 的實(shí)例;字節串只能包含 ASCII 字符;字節串數值大于等于 128 時(shí),必須用轉義表示。

字符串和字節串都可以加前綴 'r''R',稱(chēng)為 原始字符串,原始字符串把反斜杠當作原義字符,不執行轉義操作。因此,原始字符串不轉義 '\U''\u'。與 Python 2.x 的原始 unicode 字面值操作不同,Python 3.x 現已不支持 'ur' 句法。

3.3 新版功能: 新增原始字節串 'rb' 前綴,是 'br' 的同義詞。

3.3 新版功能: 支持 unicode 字面值(u'value')遺留代碼,簡(jiǎn)化 Python 2.x 和 3.x 并行代碼庫的維護工作。詳見(jiàn) PEP 414。

前綴為 'f''F' 的字符串稱(chēng)為 格式字符串;詳見(jiàn) 格式字符串字面值。'f' 可與 'r' 連用,但不能與 'b''u' 連用,因此,可以使用原始格式字符串,但不能使用格式字節串字面值。

三引號字面值可以包含未轉義的換行和引號(原樣保留),除了連在一起的,用于終止字面值的,未經(jīng)轉義的三個(gè)引號。("引號" 是啟用字面值的字符,可以是 ',也可以是 "。)

如未標注 'r''R' 前綴,字符串和字節串字面值中,轉義序列以類(lèi)似 C 標準的規則進(jìn)行解釋??捎玫霓D義序列如下:

轉義序列

含意

備注

\newline

忽略反斜杠與換行符

\\

反斜杠(\

\'

單引號('

\"

雙引號("

\a

ASCII 響鈴(BEL)

\b

ASCII 退格符(BS)

\f

ASCII 換頁(yè)符(FF)

\n

ASCII 換行符(LF)

\r

ASCII 回車(chē)符(CR)

\t

ASCII 水平制表符(TAB)

\v

ASCII 垂直制表符(VT)

\ooo

八進(jìn)制數 ooo 字符

(1,3)

\xhh

十六進(jìn)制數 hh 字符

(2,3)

字符串字面值專(zhuān)用的轉義序列:

轉義序列

含意

備注

\N{name}

Unicode 數據庫中名為 name 的字符

(4)

\uxxxx

16 位十六進(jìn)制數 xxxx 碼位的字符

(5)

\Uxxxxxxxx

32 位 16 進(jìn)制數 xxxxxxxx 碼位的字符

(6)

注釋?zhuān)?/p>

  1. 與 C 標準一致,接受最多三個(gè)八進(jìn)制數字。

    在 3.11 版更改: Octal escapes with value larger than 0o377 produce a DeprecationWarning. In a future Python version they will be a SyntaxWarning and eventually a SyntaxError.

  2. 與 C 標準不同,必須為兩個(gè)十六進(jìn)制數字。

  3. 字節串 字面值中,十六進(jìn)制數和八進(jìn)制數的轉義碼以相應數值代表每個(gè)字節。字符串 字面值中,這些轉義碼以相應數值代表每個(gè) Unicode 字符。

  4. 在 3.3 版更改: 加入了對別名 1 的支持。

  5. 必須為 4 個(gè)十六進(jìn)制數碼。

  6. 表示任意 Unicode 字符。必須為 8 個(gè)十六進(jìn)制數碼。

與 C 標準不同,無(wú)法識別的轉義序列在字符串里原樣保留,即,輸出結果保留反斜杠。(調試時(shí),這種方式很有用:輸錯轉義序列時(shí),更容易在輸出結果中識別錯誤。)注意,在字節串字面值內,字符串字面值專(zhuān)用的轉義序列屬于無(wú)法識別的轉義序列。

在 3.6 版更改: 無(wú)法識別的轉義序列觸發(fā) DeprecationWarning。未來(lái)的 Python 發(fā)行版將改為觸發(fā) SyntaxWarning,最終會(huì )改為觸發(fā) SyntaxError。

即使在原始字面值中,引號也可以用反斜杠轉義,但反斜杠會(huì )保留在輸出結果里;例如 r"\"" 是由兩個(gè)字符組成的有效字符串字面值:反斜杠和雙引號;r"\" 則不是有效字符串字面值(原始字符串也不能以奇數個(gè)反斜杠結尾)。尤其是,原始字面值不能以單個(gè)反斜杠結尾 (反斜杠會(huì )轉義其后的引號)。還要注意,反斜杠加換行在字面值中被解釋為兩個(gè)字符,而 不是 連續行。

2.4.2. 字符串字面值合并?

以空白符分隔的多個(gè)相鄰字符串或字節串字面值,可用不同引號標注,等同于合并操作。因此,"hello" 'world' 等價(jià)于 "helloworld"。此功能不需要反斜杠,即可將長(cháng)字符串分為多個(gè)物理行,還可以為不同部分的字符串添加注釋?zhuān)纾?/p>

re.compile("[A-Za-z_]"       # letter or underscore
           "[A-Za-z0-9_]*"   # letter, digit or underscore
          )

注意,此功能在句法層面定義,在編譯時(shí)實(shí)現。在運行時(shí),合并字符串表達式必須使用 '+' 運算符。還要注意,字面值合并可以為每個(gè)部分應用不同的引號風(fēng)格(甚至混用原始字符串和三引號字符串),格式字符串字面值也可以與純字符串字面值合并。

2.4.3. 格式字符串字面值?

3.6 新版功能.

格式字符串字面值 或稱(chēng) f-string 是標注了 'f''F' 前綴的字符串字面值。這種字符串可包含替換字段,即以 {} 標注的表達式。其他字符串字面值只是常量,格式字符串字面值則是可在運行時(shí)求值的表達式。

除非字面值標記為原始字符串,否則,與在普通字符串字面值中一樣,轉義序列也會(huì )被解碼。解碼后,用于字符串內容的語(yǔ)法如下:

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 | NULL | replacement_field)*
literal_char      ::=  <any code point except "{", "}" or NULL>

雙花括號 '{{''}}' 被替換為單花括號,花括號外的字符串仍按字面值處理。單左花括號 '{' 標記以 Python 表達式開(kāi)頭的替換字段。在表達式后加等于號 '=',可在求值后,同時(shí)顯示表達式文本及其結果(用于調試)。 隨后是用嘆號 '!' 標記的轉換字段。還可以在冒號 ':' 后附加格式說(shuō)明符。替換字段以右花括號 '}' 為結尾。

格式字符串字面值中,表達式的處理與圓括號中的常規 Python 表達式基本一樣,但也有一些不同的地方。不允許使用空表達式;lambda 和賦值表達式 := 必須顯式用圓括號標注;替換表達式可以包含換行(例如,三引號字符串中),但不能包含注釋?zhuān)辉诟袷阶址置嬷嫡Z(yǔ)境內,按從左至右的順序,為每個(gè)表達式求值。

在 3.7 版更改: Python 3.7 以前, 因為實(shí)現的問(wèn)題,不允許在格式字符串字面值表達式中使用 await 表達式與包含 async for 子句的推導式。

表達式里含等號 '=' 時(shí),輸出內容包括表達式文本、'=' 、求值結果。輸出內容可以保留表達式中左花括號 '{' 后,及 '=' 后的空格。沒(méi)有指定格式時(shí),'=' 默認調用表達式的 repr()。指定了格式時(shí),默認調用表達式的 str(),除非聲明了轉換字段 '!r'。

3.8 新版功能: 等號 '='。

指定了轉換符時(shí),表達式求值的結果會(huì )先轉換,再格式化。轉換符 '!s' 調用 str() 轉換求值結果,'!r' 調用 repr(),'!a' 調用 ascii()。

輸出結果的格式化使用 format() 協(xié)議。格式說(shuō)明符傳入表達式或轉換結果的 __format__() 方法。省略格式說(shuō)明符,則傳入空字符串。然后,格式化結果包含在整個(gè)字符串的最終值里。

頂層格式說(shuō)明符可以包含嵌套替換字段。嵌套字段也可以包含自己的轉換字段和 格式說(shuō)明符,但不可再包含更深層嵌套的替換字段。格式說(shuō)明符微語(yǔ)言str.format() 方法使用的微語(yǔ)言相同。

格式化字符串字面值可以拼接,但是一個(gè)替換字段不能拆分到多個(gè)字面值。

格式字符串字面值示例如下:

>>>
>>> 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" '

與常規字符串字面值的語(yǔ)法一樣,替換字段中的字符不能與外層格式字符串字面值的引號沖突:

f"abc {a["x"]} def"    # error: outer string literal ended prematurely
f"abc {a['x']} def"    # workaround: use different quoting

格式表達式中不能有反斜杠,否則會(huì )報錯:

f"newline: {ord('\n')}"  # raises SyntaxError

要使用反斜杠轉義的值,則需創(chuàng )建臨時(shí)變量。

>>>
>>> newline = ord('\n')
>>> f"newline: {newline}"
'newline: 10'

即便未包含表達式,格式字符串字面值也不能用作文檔字符串。

>>>
>>> def foo():
...     f"Not a docstring"
...
>>> foo.__doc__ is None
True

參閱 PEP 498,了解格式字符串字面值的提案,以及與格式字符串機制相關(guān)的 str.format()。

2.4.4. 數值字面值?

數值字面值有三種類(lèi)型:整數、浮點(diǎn)數、虛數。沒(méi)有復數字面值(復數由實(shí)數加虛數構成)。

注意,數值字面值不含正負號;實(shí)際上,-1 等負數是由一元運算符 '-' 和字面值 1 合成的。

2.4.5. 整數字面值?

整數字面值詞法定義如下:

integer      ::=  decinteger | bininteger | octinteger | hexinteger
decinteger   ::=  nonzerodigit (["_"] digit)* | "0"+ (["_"] "0")*
bininteger   ::=  "0" ("b" | "B") (["_"] bindigit)+
octinteger   ::=  "0" ("o" | "O") (["_"] octdigit)+
hexinteger   ::=  "0" ("x" | "X") (["_"] hexdigit)+
nonzerodigit ::=  "1"..."9"
digit        ::=  "0"..."9"
bindigit     ::=  "0" | "1"
octdigit     ::=  "0"..."7"
hexdigit     ::=  digit | "a"..."f" | "A"..."F"

整數字面值的長(cháng)度沒(méi)有限制,能一直大到占滿(mǎn)可用內存。

確定數值時(shí),會(huì )忽略字面值中的下劃線(xiàn)。下劃線(xiàn)只是為了分組數字,讓數字更易讀。下劃線(xiàn)可在數字之間,也可在 0x 等基數說(shuō)明符后。

注意,除了 0 以外,十進(jìn)制數字的開(kāi)頭不允許有零。以免與 Python 3.0 版之前使用的 C 樣式八進(jìn)制字面值混淆。

整數字面值示例如下:

7     2147483647                        0o177    0b100110111
3     79228162514264337593543950336     0o377    0xdeadbeef
      100_000_000_000                   0b_1110_0101

在 3.6 版更改: 現已支持在字面值中,用下劃線(xiàn)分組數字。

2.4.6. 浮點(diǎn)數字面值?

浮點(diǎn)數字面值詞法定義如下:

floatnumber   ::=  pointfloat | exponentfloat
pointfloat    ::=  [digitpart] fraction | digitpart "."
exponentfloat ::=  (digitpart | pointfloat) exponent
digitpart     ::=  digit (["_"] digit)*
fraction      ::=  "." digitpart
exponent      ::=  ("e" | "E") ["+" | "-"] digitpart

注意,解析時(shí),整數和指數部分總以 10 為基數。例如,077e010 是合法的,表示的數值與 77e10 相同。浮點(diǎn)數字面值的支持范圍取決于具體實(shí)現。整數字面值支持用下劃線(xiàn)分組數字。

浮點(diǎn)數字面值示例如下:

3.14    10.    .001    1e100    3.14e-10    0e0    3.14_15_93

在 3.6 版更改: 現已支持在字面值中,用下劃線(xiàn)分組數字。

2.4.7. 虛數字面值?

虛數字面值詞法定義如下:

imagnumber ::=  (floatnumber | digitpart) ("j" | "J")

虛數字面值生成實(shí)部為 0.0 的復數。復數由一對浮點(diǎn)數表示,它們的取值范圍相同。創(chuàng )建實(shí)部不為零的復數,則需添加浮點(diǎn)數,例如 (3+4j)。虛數字面值示例如下:

3.14j   10.j    10j     .001j   1e100j   3.14e-10j   3.14_15_93j

2.5. 運算符?

運算符如下所示:

+       -       *       **      /       //      %      @
<<      >>      &       |       ^       ~       :=
<       >       <=      >=      ==      !=

2.6. 分隔符?

以下形符在語(yǔ)法中為分隔符:

(       )       [       ]       {       }
,       :       .       ;       @       =       ->
+=      -=      *=      /=      //=     %=      @=
&=      |=      ^=      >>=     <<=     **=

句點(diǎn)也可以用于浮點(diǎn)數和虛數字面值。三個(gè)連續句點(diǎn)表示省略符。列表后半部分是增強賦值操作符,用作詞法分隔符,但也可以執行運算。

以下 ASCII 字符具有特殊含義,對詞法分析器有重要意義:

'       "       #       \

以下 ASCII 字符不用于 Python。在字符串字面值或注釋外使用時(shí),將直接報錯:

$       ?       `

備注

1

https://www.unicode.org/Public/11.0.0/ucd/NameAliases.txt