# 2. 词法分析

Python 程序将由一个 解析器 来读取。 输入解析器的是 词元 的流，由 词法分析器 (或称 分词器) 生成。 本章将介绍词法分析器是如何产生词元的。

词法分析器会确定程序文本的 编码格式 (默认为 UTF-8)，并将文本解码为 源字符。 如果文本无法解码，将会引发 `SyntaxError`。

接下来，词法分析器将使用源字符生成词元流。 所生成的词元类型取决于下一个要处理的源字符。 类似地，分析器的其他特殊行为取决于尚未被处理的第一个源字符。 下面的表格给出了这些源字符串的概要，并带有包含更多信息的章节链接。

字符 | 下一词元（或其他相关文档）
--- | ---
space tab formfeed | 空格
CR, LF | 换行 缩进
反斜杠 (`\`) | 显式行合并 (也用于 字符串转义序列)
井号 (`#`) | 注释
引号 (`'`, `"`) | 字符串字面值
ASCII 字母 (`a`-`z`, `A`-`Z`) 非 ASCII 字符 | 名称 带前缀的 字符串或字节串字面值
下划线 (`_`) | 名称 (也可作为 数字字面值 的组成部分)
数字 (`0`-`9`) | 数字字面值
点号 (`.`) | 数字字面值 运算符
问号 (`?`) 货币符 (`$`) 反引号 (`​`​`) 控制字符 | 错误（在字符串字面值和注释之外）
其他可打印字符 | 运算符或分隔符
文件结束 | 结束标记

## 2.1. 行结构

Python 程序可以拆分为多个 逻辑行。

### 2.1.1. 逻辑行

逻辑行的结束由词元 `NEWLINE` 表示。 除非语法允许 `NEWLINE` (举例来说，在复合语句中的多个语句之前) 否则语句不能跨越逻辑行边界。 逻辑行由一条或多条 物理行 根据 显示 或 隐式 的 行连接 规则构造而成。

### 2.1.2. 物理行

物理行是由使用下列行结束符序列中的一个作为终结的字符序列：

- 使用 ASCII LF (linefeed) 的 Unix 形式，

- 使用 ASCII 序列 CR LF (return 加 linefeed) 的 Windows 形式，

- 使用 ASCII CR (return) 字符的 'Classic Mac OS' 形式。

无论平台如何，这些序列中的每一个都会被替换为单个ASCII LF（换行）字符。（即使在 字符串字面量 中也是如此。）每一行可以使用这些序列中的任何一个；它们在文件内部不需要保持一致。

输入的结束也作为最后一个物理行的隐式终止符。

形式上：

    newline: <ASCII LF> | <ASCII CR> <ASCII LF> | <ASCII CR>

### 2.1.3. 注释

注释以井号 （`#`） 开头，在物理行末尾截止。注意，井号不是字符串字面量。除非应用隐式行拼接规则，否则，注释代表逻辑行结束。句法不解析注释。

### 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:   # 看来是个有效的日期
            return 1

以反斜杠结尾的行不能包含注释。反斜杠不能用于延续注释内容。除字符串字面量之外，反斜杠不能用于延续标记（即非字符串字面量的标记不能通过反斜杠拆分到物理行的下一行）。在字符串字面量之外的行中，反斜杠出现在其他位置是非法的。

### 2.1.6. 隐式拼接行

圆括号、方括号、花括号内的表达式可以分成多个物理行，不必使用反斜杠。例如：

    month_names = ['Januari', 'Februari', 'Maart',      # 这些是
                   'April',   'Mei',      'Juni',       # 一年之中
                   'Juli',    'Augustus', 'September',  # 各个月份的
                   'Oktober', 'November', 'December']   # 荷兰语名称

隐式行拼接可含注释；后续行的缩进并不重要；还支持空的后续行。隐式拼接行之间没有 NEWLINE 标记。三引号字符串支持隐式拼接行（见下文），但不支持注释。

### 2.1.7. 空白行

仅包含空格、制表符、换页符以及可能的注释的逻辑行将被忽略（即不会生成 `NEWLINE` 标记）。在交互式输入语句时，空行的处理方式可能因读取-求值-打印循环的实现而异。在标准交互式解释器中，完全空白的逻辑行（即不包含任何空白符或注释）会终止多行语句。

### 2.1.8. 缩进

逻辑行开头的空白符（空格符和制表符）用于计算该行的缩进层级，决定语句组块。

制表符（从左至右）被替换为一至八个空格，缩进空格的总数是八的倍数（与 Unix 的规则保持一致）。首个非空字符前的空格数决定了该行的缩进层次。缩进不能用反斜杠进行多行拼接；首个反斜杠之前的空白符决定了缩进的层次。

源文件混用制表符和空格符缩进时，因空格数量与制表符相关，由此产生的不一致将导致不能正常识别缩进层次，从而触发 `TabError`。

跨平台兼容性说明： 鉴于非 UNIX 平台文本编辑器本身的特性，请勿在源文件中混用制表符和空格符。另外也请注意，不同平台有可能会显式限制最大缩进层级。

行首含换页符时，缩进计算将忽略该换页符。换页符在行首空白符内其他位置的效果未定义（例如，可能导致空格计数重置为零）。

连续行的缩进级别使用一个栈来生成 `INDENT` 和 `DEDENT` 标记，规则如下。

Before the first line of the file is read, a single zero is pushed on the stack; this will never be popped off again. The numbers pushed on the stack will always be strictly increasing from bottom to top. At the beginning of each logical line, the line's indentation level is compared to the top of the stack. If it is equal, nothing happens. If it is larger, it is pushed on the stack, and one `INDENT` token is generated. If it is smaller, it must be one of the numbers occurring on the stack; all numbers on the stack that are larger are popped off, and for each number popped off a `DEDENT` token is generated. At the end of the file, a `DEDENT` token is generated for each number remaining on the stack that is larger than zero.

下面的 Python 代码缩进示例虽然正确，但含混不清：

    def perm(l):
            # 计算由 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):                       # 错误：第一行有缩进
    for i in range(len(l)):             # 错误：没有缩进
        s = l[:i] + l[i+1:]
            p = perm(l[:i] + l[i+1:])   # 错误：非预期的缩进
            for x in p:
                    r.append(l[i:i+1] + x)
                return r                # 错误：不一致的缩进

（实际上，解析器可以识别前三个错误；只有最后一个错误由词法分析器识别 --- `return r` 的缩进无法匹配从栈里移除的缩进层级。）

### 2.1.9. 标记间的空白字符

除非是在逻辑行的开头或字符串字面值中，空白字符、制表符和进纸符可以交换作为不同的词元：

    whitespace:  ' ' | tab | formfeed

两个词元之间仅在它们的拼接可能被解读为另一个不同的标记时才需要使用空白符。 例如，`ab` 是一个词元，而 `a b` 是两个词元。 不过，`+a` 和 `+ a` 都将产生两个词元，`+` 和 `a`，因为 `+a` 不是一个有效的词元。

### 2.1.10. 结束标记

在非交互输入结束时，词法分析器将生成一个 `ENDMARKER` 词元。

## 2.2. 其他标记

除了 `NEWLINE`、`INDENT` 和 `DEDENT` 之外，还存在以下几类词元: 标识符 和 关键字 (`NAME`)、字面量 (如 `NUMBER` 和 `STRING`)，以及其他符号 (运算符 和 分隔符, `OP`)。 空白字符（除了前面讨论的逻辑行终止符）不是词元，而是用于分隔词元。 在有歧义的情况下，词元由从左到右读取时能形成合法词元的最长可能字符串组成。

## 2.3. 名称（标识符和关键字）

`NAME` 标记表示 标识符、关键字 和 软关键字。

名称是由以下字符组成的：

- 大写和小写字母 (`A-Z` 和 `a-z`)。

- 下划线 (`_`)。

- 数字 (`0` 至 `9`)，但不能作为第一个字符，以及

- 非 ASCII 字符。 合法的名称只能包含“字母型”和“数字型”字符；请参阅 名称中的非 ASCII 字符 了解详情。

名称必须至少包含一个字符，但没有长度上限。大小写敏感。

形式上，名称由以下词法定义描述：

    NAME:          name_start name_continue*
    name_start:    "a"..."z" | "A"..."Z" | "_" | <non-ASCII character>
    name_continue: name_start | "0"..."9"
    identifier:    <NAME, except keywords>

请注意并非所有匹配此语法的名称都是合法的；请参阅 名称中的非 ASCII 字符 了解详情。

### 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. 软关键字

Added in version 3.10.

某些名称仅在特定上下文中保留。这些被称为 软关键字：

- `match`、`case` 和 `_` 在 `match` 语句中使用时属于软关键字。

- `type` 在 `type` 语句中使用时属于软关键字。

这些标识符在特定上下文中语法上作为关键字使用，但这种区分是在解析器层面完成的，而非词法分析（分词）阶段。

作为软关键字，它们能够在用于相应语法的同时仍然保持与用作标识符名称的现有代码的兼容性。

在 3.12 版本发生变更: `type` 现在是一个软关键字。

### 2.3.3. 保留的标识符类

某些标识符类（除了关键字）具有特殊含义。这些类的命名模式以下划线字符开头，并以下划线结尾：

`_*`

  不会被 `from module import *` 所导入。

`_`

  在 `match` 语句内部的 `case` 模式中，`_` 是一个 软关键字，它表示 通配符。

  在此之外，交互式解释器会将最后一次求值的结果放到变量 `_` 中。 （它与 `print` 等内置函数一起被存储于 `builtins` 模块。）

  在其他地方，`_` 是一个常规标识符。 它常常被用来命名 "特殊" 条目，但对 Python 本身来说毫无特殊之处。

  备注

  `_` 常用于连接国际化文本；详见 `gettext` 模块文档。

  它还经常被用来命名无需使用的变量。

`__*__`

  系统定义的名称，通常简称为 "dunder" 。这些名称由解释器及其实现（包括标准库）定义。现有系统定义名称相关的论述详见 特殊方法名称 等章节。Python 未来版本中还将定义更多此类名称。任何情况下，任何 不显式遵从 `__*__` 名称的文档用法，都可能导致无警告提示的错误。

`__*`

  类的私有名称。类定义时，此类名称以一种混合形式重写，以避免基类及派生类的 "私有" 属性之间产生名称冲突。详见 标识符（名称）。

### 2.3.4. 名称中的非 ASCII 字符

包含非非 ASCII 字符的名称在 上文 所述规则和语法说明之上还需要额外的规范化和验证。 例如，`ř_1`, `蛇` 或 `साँप` 是合法的名称，但 `r〰2`, `€` 或 `🐍` 则不是。

本节介绍具体的规则。

在解析时所有名称都会被转换为 normalization form NFKC。 例如，这意味着某些字符的排印形式将被转换为其“基本”形式。 举例来说，`ﬁⁿₐˡᵢᶻₐᵗᵢᵒₙ` 将被正规化为 `finalization`，因此 Python 会将它们视为相同的名称:

    >>> ﬁⁿₐˡᵢᶻₐᵗᵢᵒₙ = 3
    >>> finalization
    3

备注

正规化仅会在词法层级上进行。 接受 字符串 形式名称的运行时函数通常不会正规化其参数。 例如，在运行时上面定义的变量在 `globals()` 字典中可通过 `globals()["finalization"]` 访问但不可通过 `globals()["ﬁⁿₐˡᵢᶻₐᵗᵢᵒₙ"]` 访问。

与纯 ASCII 的名称仅能包含字母、数字和下划线，且不能以数字打头类似，合法的名称必须以“字母型”集合 `xid_start` 中的字符打头，且其余的字符必须属于“字母数字型”集合 `xid_continue`。

这两个集合以 Unicode 标准附件 UAX-31 所定义的 XID_Start 和 XID_Continue 集合为基础。 Python 的 `xid_start` 还包括了下划线 (`_`)。 请注意 Python 并未与 UAX-31 保持一致。

Unicode 字符数据库中的 DerivedCoreProperties.txt 文件提供了由 Unicode 定义的 XID_Start 和 XID_Continue 集内字符的非规范性列表。 作为参考，`xid_*` 集合的构造规则如下。

集合 `id_start` 被定义为以下内容的并集：

- Unicode 类别 `<Lu>` - 大写字母 (包括 `A` 到 `Z`)

- Unicode 类别 `<Ll>` - 小写字母 (包括 `a` 到 `z`)

- Unicode 类别 `<Lt>` - 标题大小写字母

- Unicode 类别 `<Lm>` - 修饰字母

- Unicode category `<Lo>` - 其他字母

- Unicode 类别 `<Nl>` - 数字字母

- {`"_"`} - 下划线

- `<Other_ID_Start>` - 在 PropList.txt 中显式定义的用于支持向下兼容的字符集合

集合 `xid_start` 随后以 NFKC 规范化关闭此集合，将移除规范化形式不是 `id_start id_continue*` 的所有字符。

集合 `id_continue` 被定义为以下内容的并集：

- `id_start` (见上文)

- Unicode 类别 `<Nd>` - 十进制数字（包括 `0` 到 `9`）

- Unicode 类别 `<Pc>` - 连接标点符号

- Unicode 类别 `<Mn>` - 非间距标记

- Unicode 类别 `<Mc>` - 间距组合标记

- `<Other_ID_Continue>` - 为支持向下兼容性在 PropList.txt 中另一组显式列出的字符集合

同样地，`xid_continue` 以 NFKC 规范化关闭此集合。

Unicode 类别使用的是 `unicodedata` 模块中所包含的 Unicode 字符数据库版本。

参见

- PEP 3131 -- 支持非 ASCII 标识符

- PEP 672 -- 针对 Python 的 Unicode 相关安全考量

## 2.4. 字面量

字面量是内置类型常量值的表示法。

在词法分析方面，Python有 字符串、字节 和 数值 字面量。

其他“字面量”通过 关键字 (`None`、`True`、`False`) 和特殊的 省略号标记 (`...`) 进行词法表示。

## 2.5. 字符串与字节串字面量

字符串字面量是用单引号（`'`）或双引号（`"`）括起来的文本。例如：

    "spam"
    'eggs'

用于开始字面量的引号也用于终止它，因此字符串字面量只能包含另一个引号（除非使用转义序列，见下文）。例如：

    'Say "Hello", please.'
    "Don't do that!"

除了这个限制外，引号字符（`'` 或 `"`）的选择不影响字面量的解析方式。

在字符串字面量内部，反斜杠（`\`）字符引入了一个 转义序列，其特殊含义取决于反斜杠后面的字符。例如，`\"` 表示双引号字符，并且 不 结束字符串：

    >>> print("Say \"Hello\" to everyone!")
    Say "Hello" to everyone!

有关此类序列的完整列表和更多详细信息，请参见下文的 转义序列。

### 2.5.1. 三引号字符串

字符串也可以用三组匹配的单引号或双引号括起来。这些通常被称为 三引号字符串:

    """这是一个三引号字符串。"""

在三引号字面量中，允许使用未转义的引号（并且会保留），但与起始引号相同的三个连续未转义引号（`'` 或 `"`）会终止字面量:

    """这个字符串内有 "引号"。"""

也允许使用未转义的新行，并且会保留:

    '''这个三引号字符串
    在下一行继续。'''

### 2.5.2. 字符串前缀

字符串字面量可以有一个可选的 前缀，该前缀会影响字面量内容的解析方式，例如:

    b"data"
    f'{result=}'

允许的前缀有:

- `b`: 字节串字面量

- `r`: 原始字符串

- `f`: 格式字符串字面量 ("f-string")

- `t`: 模板字符串字面量 ("t-string")

- `u`: 无效果（为向后兼容而允许）

详细信息请参见链接部分。

前缀不区分大小写（例如，'`B`' 与 '`b`' 效果相同）。 '`r`' 前缀可以与 '`f`', '`t`' 或 '`b`' 组合使用，因此 '`fr`', '`rf`', '`tr`', '`rt`', '`br`' 和 '`rb`' 也是有效的前缀。

Added in version 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:      <any source_character, except backslash and newline>
    longstringitem:  stringitem | newline
    stringescapeseq: "\" <any source_character>

请注意，与所有词法定义一样，空白符是重要的。特别是，前缀（如果有）必须紧接起始引号。

### 2.5.4. 转义序列

除非存在 '`r`' 或 '`R`' 前缀，在字符串和字节串字面值中的转义序列将按照类似于标准 C 所使用的规则进行解读。 可用的转义序列有：

转义序列 | 含意
--- | ---
`\`<newline> | 字符串转义 - 忽略模式
`\\` | 反斜杠
`\'` | 单引号
`\"` | 双引号
`\a` | ASCII 响铃（BEL）
`\b` | ASCII 退格符（BS）
`\f` | ASCII 换页符（FF）
`\n` | ASCII 换行符（LF）
`\r` | ASCII 回车符（CR）
`\t` | ASCII 水平制表符（TAB）
`\v` | ASCII 垂直制表符（VT）
`\ooo` | 字符串转义 - 八进制
`\xhh` | 字符串转义 - 十六进制
`\N{name}` | 字符串转义 - 命名字符
`\uxxxx` | 十六进制 Unicode 字符
`\Uxxxxxxxx` | 十六进制 Unicode 字符

#### 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}` 表示具有给定 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-字符串

Added in version 3.6.

在 3.7 版本发生变更: `await` 和 `async for` 可在 f-字符串内部的表达式中使用。

在 3.8 版本发生变更: 增加了调试说明符 (`=`)

在 3.12 版本发生变更: 许多针对 f-字符串内部的表达式的限制已被移除。 例如，嵌套字符串、注释和反斜杠现在都是允许的。

格式化字符串字面值 或称 f-字符串 是带有 '`f`' 或 '`F`' 前缀的字符串字面值。 不同于其他字符串字面值，f-字符串的值不是固定的。 它们可能包含由花括号 `{}` 标记的 替换字段。 替换字段包含要在运行时被求值的表达式。 例如:

    >>> who = 'nobody'
    >>> nationality = 'Spanish'
    >>> f'{who.title()} expects the {nationality} Inquisition!'
    'Nobody expects the Spanish Inquisition!'

任何在替换字段之外的双花括号 (`{{` 或 `}}`) 都将以相应的单花括号替换:

    >>> print(f'{{...}}')
    {...}

替换字段之外的其他字符将被当作是普通的字符串字面值。 这意味着转义序列会被解码（除非该字面值还被标记为原始字符串），在三重引号 f-字符串中还可以换行:

    >>> name = 'Galahad'
    >>> favorite_color = 'blue'
    >>> print(f'{name}:\t{favorite_color}')
    Galahad:       blue
    >>> print(rf"C:\Users\{name}")
    C:\Users\Galahad
    >>> print(f'''Three shall be the number of the counting
    ... and the number of the counting shall be three.''')
    Three shall be the number of the counting
    and the number of the counting shall be three.

格式化字符串字面值中的表达式将被当作是常规的 Python 表达式。 每个表达式都将在格式化字符串字面值所在的上下文中以从左至右的顺序被求值。 空表达式不被允许，而 `lambda` 和赋值表达式 `:=` 必须显式地以圆括号标记:

    >>> f'{(half := 1/2)}, {half * 42}'
    '0.5, 21.0'

允许在替换字段中重用外层 f-字符串的引号类型:

    >>> a = dict(x=2)
    >>> f"abc {a["x"]} def"
    'abc 2 def'

替换字段中也允许使用反斜杠并会以与在其他场景下相同的方式求值:

    >>> a = ["a", "b", "c"]
    >>> print(f"List a contains:\n{"\n".join(a)}")
    List a contains:
    a
    b
    c

也可以嵌套 f-字符串:

    >>> name = 'world'
    >>> f'Repeated:{f' hello {name}' * 3}'
    'Repeated: hello world hello world hello world'

可移植的 Python 程序不应使用超过 5 层的嵌套。

CPython 不限制 f-字符串的嵌套层级。

在单个引号和三重引号 f-字符串中的替换表达式都可包含换行并可包含注释。 替换字段内部在 `#` 之后的任何内容都属于注释（包括花括号和引号）。 这意味着带有注释的替换字段必须另起一行来结束：

    >>> a = 2
    >>> f"abc{a  # 在此行结束前此注释  }"  将保持有效
    ...       + 3}"
    'abc5'

在表达式之后，替换字段还可以包含：

- 调试说明符 -- 一个等号 (`=`)，可以在一侧或两侧加空格；

- 一个 转换说明符 -- `!s`, `!r` 或 `!a`；和/或

- 一个以冒号 (`:`) 作为前缀的 格式说明符。

请参阅 标准库中的 f-字符串一节 了解这些字段如何被求值的详情。

如该小节所说的，格式说明符 将作为传给 `format()` 函数的第二个参数用来格式化替换字段值。 例如，它们可通过使用 格式说明微语言 来指明字段宽度和填充字符:

    >>> number = 14.3
    >>> f'{number:20.7f}'
    '          14.3000000'

顶层的格式说明符可以包括嵌套的替换字段:

    >>> field_size = 20
    >>> precision = 7
    >>> f'{number:{field_size}.{precision}f}'
    '          14.3000000'

这些嵌套的字段还可以包括它们自己的转换字段和 格式说明符:

    >>> number = 3
    >>> f'{number:{field_size}}'
    '                   3'
    >>> f'{number:{field_size:05}}'
    '00000000000000000003'

不过，这些嵌套的字段不可以包括更深一级的嵌套替换字段。

格式字符串字面值不能被用作 文档字符串，即使其中未包括表格式:

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

参见

- PEP 498 -- 字符串字面值插值

- PEP 701 -- f-字符串的语法形式化

- `str.format()`，它使用了关联的格式字符串机制。

### 2.5.8. t-strings

Added in version 3.14.

模板字符串字面值 或称 t-字符串 是以 '`t`' 或 '`T`' 作为前缀的字符串字面值。 这些字符串遵循与 格式化字符串字面值 相同的语法规则。 有关求值规则的差异，请参见 标准库的 t-字符串章节

### 2.5.9. f-字符串的正式语法

对 f-字符串处理一部分由 lexical analyzer 进行，它会产生 `FSTRING_START`, `FSTRING_MIDDLE` 和 `FSTRING_END` 等词元，另一部分由解析器进行，它将处理替换字段中的表达式。 具体的工作划分方式属于 CPython 实现细节。

相应地，f-字符串语法是 词法和语法定义 的混合体。

空格在这些场合中是有意义的：

- 在 `FSTRING_START` 中不能有空格（即前缀和引号之间）。

- 在 `FSTRING_MIDDLE` 中的空格是字符串字面值内容的一部分。

- 在 `fstring_replacement_field` 中，如果存在 `f_debug_specifier`，则左花括号之后直到 `f_debug_specifier` 的所有空格，以及 `f_debug_specifier` 后面紧随的空格，将作为表达式的一部分被保留。

  表达式不会在分词阶段被处理；它将根据 `{` 词元和 `=` 之后的词元位置从源代码中提取。

`FSTRING_MIDDLE` 定义使用 否向否定前视 (`!`) 来指明特殊字符 (反斜杠, 换行符, `{`, `}`) 以及序列 (`f_quote`)。

    fstring:    FSTRING_START fstring_middle* FSTRING_END

    FSTRING_START:      fstringprefix ("'" | '"' | "'''" | '"""')
    FSTRING_END:        f_quote
    fstringprefix:      <("f" | "fr" | "rf"), case-insensitive>
    f_debug_specifier:  '='
    f_quote:            <the quote character(s) used in FSTRING_START>

    fstring_middle:
       | fstring_replacement_field
       | FSTRING_MIDDLE
    FSTRING_MIDDLE:
       | (!"\" !newline !'{' !'}' !f_quote) source_character
       | stringescapeseq
       | "{{"
       | "}}"
       | <newline, in triple-quoted f-strings only>
    fstring_replacement_field:
       | '{' f_expression [f_debug_specifier] [fstring_conversion]
             [fstring_full_format_spec] '}'
    fstring_conversion:
       | "!" ("s" | "r" | "a")
    fstring_full_format_spec:
       | ':' fstring_format_spec*
    fstring_format_spec:
       | FSTRING_MIDDLE
       | fstring_replacement_field
    f_expression:
       | ','.(conditional_expression | "*" or_expr)+ [","]
       | yield_expression

备注

在上面的语法片段中， `f_quote` 和 `FSTRING_MIDDLE` 规则是对上下文敏感的 -- 它们依赖于最近的外层 `fstring` 的 `FSTRING_START` 的内容。

根据此模板构造更传统的正式语法将作为留给读者的练习。

针对 t-字符串的语法与 f-字符串的语法类似，只是以 t 而不是 f 作为规则和词元名称和前缀的开头。

    tstring:    TSTRING_START tstring_middle* TSTRING_END

    <rest of the t-string grammar is omitted; see above>

## 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.  # (等同于 10.0)
    .001  # (等同于 0.001)

整数部分和小数部分之后可以选择性地跟随一个 指数部分：字母 `e` 或 `E`，后面跟一个可选的符号（`+` 或 `-`），以及一个格式与整数和小数部分相同的数字。这里的 `e` 或 `E` 表示"乘以10的...次幂":

    1.0e3  # (代表 1.0×10³, or 1000.0)
    1.166e-5  # (代表 1.166×10⁻⁵, or 0.00001166)
    6.02214076e+23  # (代表 6.02214076×10²³ 或 602214076000000000000000)

对于仅包含整数部分和指数部分的浮点字面量，小数点可以省略:

    1e3  # (等同于 1.e3 和 1.0e3)
    0e0  # (等同于 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   # 等同于 1e+24j

`j` 后缀在语法上是大小写不敏感的。这意味着你可以使用 `J` 替代:

    3.14J   # 等同于 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` 字面值的特殊含义。