2. 词法分析

Python 程序由解析器读取。解析器的输入是由词法分析器生成的标记流。本章描述词法分析器如何将文件分解为标记。

Python 将程序文本读取为 Unicode 代码点;源文件的编码可以通过编码声明指定,默认为 UTF-8,详情请参阅PEP 3120。如果源文件无法解码,则会引发SyntaxError

2.1. 行结构

Python 程序被划分为多个逻辑行

2.1.1. 逻辑行

逻辑行的末尾由标记 NEWLINE 表示。语句不能跨越逻辑行边界,除非语法允许 NEWLINE(例如,复合语句中的语句之间)。逻辑行由一个或多个物理行通过遵循显式或隐式的行连接规则构成。

2.1.2. 物理行

物理行是由行尾序列终止的字符序列。在源文件和字符串中,可以使用任何标准平台行终止序列 - Unix 形式使用 ASCII LF(换行符)、Windows 形式使用 ASCII 序列 CR LF(回车后跟换行符)或旧 Macintosh 形式使用 ASCII CR(回车)字符。所有这些形式都可以平等使用,而与平台无关。输入的末尾也作为最后一个物理行的隐式终止符。

嵌入 Python 时,应使用标准 C 约定来表示换行符(\n 字符,表示 ASCII LF,是行终止符)将源代码字符串传递给 Python API。

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'xefxbbxbf') 将被忽略,而不是语法错误。

如果声明了编码,则编码名称必须被 Python 识别(请参阅标准编码)。该编码用于所有词法分析,包括字符串字面值、注释和标识符。

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 是两个标记)。

2.2. 其他标记

除了 NEWLINE、INDENT 和 DEDENT 之外,还存在以下几类标记:标识符关键字字面值运算符分隔符。空格字符(前面讨论的行终止符除外)不是标记,而是用于分隔标记。如果存在歧义,则标记包含从左到右读取时形成合法标记的最长字符串。

2.3. 标识符和关键字

标识符(也称为名称)由以下词法定义描述。

Python 中标识符的语法基于 Unicode 标准附件 UAX-31,并根据以下定义进行了详细说明和更改;另请参阅 PEP 3131 以了解更多详细信息。

在 ASCII 范围 (U+0001..U+007F) 内,标识符的有效字符包括大写和小写字母 AZ、下划线 _,以及(除了第一个字符外)数字 09。 Python 3.0 引入了 ASCII 范围之外的其他字符(请参阅 PEP 3131)。对于这些字符,分类使用 unicodedata 模块中包含的 Unicode 字符数据库的版本。

标识符的长度没有限制。大小写是有意义的。

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 类别代码代表:

  • Lu - 大写字母

  • Ll - 小写字母

  • Lt - 首字母大写的字母

  • Lm - 修饰符字母

  • Lo - 其他字母

  • Nl - 字母数字

  • Mn - 非间距标记

  • Mc - 间距组合标记

  • Nd - 十进制数字

  • Pc - 连接标点符号

  • Other_ID_Start - PropList.txt 中明确的字符列表,以支持向后兼容性

  • Other_ID_Continue - 同样

所有标识符在解析时都会转换为 NFKC 范式;标识符的比较基于 NFKC。

可以在 https://www.unicode.org/Public/15.1.0/ucd/DerivedCoreProperties.txt 找到一个非规范的 HTML 文件,其中列出了 Unicode 15.1.0 的所有有效标识符字符。

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 版本中添加。

有些标识符仅在特定上下文中保留。这些被称为软关键字。标识符 matchcasetype_ 在某些上下文中可以在语法上充当关键字,但这种区分是在解析器级别完成的,而不是在标记化时完成的。

作为软关键字,它们在语法中的使用是可能的,同时仍然保持与使用这些名称作为标识符名称的现有代码的兼容性。

matchcase_match 语句中使用。typetype 语句中使用。

在 3.12 版本中更改: type 现在是一个软关键字。

2.3.3. 保留的标识符类别

某些类别的标识符(除了关键字)具有特殊的含义。这些类别通过前导和尾随下划线字符的模式来识别。

_*

不被 from module import * 导入。

_

match 语句中的 case 模式中,_ 是一个软关键字,表示一个通配符

另外,交互式解释器使上次求值的结果在变量 _ 中可用。(它存储在 builtins 模块中,以及内置函数(如 print)一起。)

在其他地方,_ 是一个常规标识符。它通常用于命名“特殊”项,但它本身对 Python 来说并不特殊。

注意

名称 _ 通常与国际化结合使用;有关此约定的更多信息,请参阅 gettext 模块的文档。

它也常用于未使用的变量。

__*__

系统定义的名称,俗称“dunder”名称。这些名称由解释器及其实现(包括标准库)定义。当前系统名称在 特殊方法名称 部分和其他地方讨论。未来版本的 Python 中可能会定义更多名称。任何 使用 __*__ 名称(在任何上下文中),如果不遵循明确记录的使用方法,都可能在没有警告的情况下中断。

__*

类私有名称。此类别中的名称在类定义的上下文中使用时,会被重写为使用经过修改的形式,以帮助避免基类和派生类的“私有”属性之间的名称冲突。请参阅 标识符(名称) 部分。

2.4. 字面值

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

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>

这些产生式中未指明的一个语法限制是,在 stringprefixbytesprefix 和字面值的其余部分之间不允许有空格。源字符集由编码声明定义;如果源文件中没有给出编码声明,则为 UTF-8;请参阅 编码声明 部分。

用通俗易懂的英语来说:两种类型的字面值都可以用匹配的单引号(')或双引号(")括起来。它们也可以用匹配的三组单引号或双引号括起来(这些通常称为三引号字符串)。反斜杠(\)字符用于赋予普通字符(如 n)特殊含义,当转义时(\n)表示“换行符”。它也可以用于转义其他具有特殊含义的字符,例如换行符、反斜杠本身或引号字符。请参阅下面的转义序列,了解示例。

字节字面值总是以 'b''B' 为前缀;它们生成 bytes 类型的实例,而不是 str 类型。它们只能包含 ASCII 字符;数值为 128 或更大的字节必须用转义符表示。

字符串和字节字面值都可以选择以字母 'r''R' 为前缀;这种结构分别称为原始字符串字面值原始字节字面值,并将反斜杠视为字面字符。因此,在原始字符串字面值中,'\U''\u' 转义符不被特殊处理。

在 3.3 版本中添加: 原始字节字面值的 'rb' 前缀已添加为 'br' 的同义词。

为了简化 Python 2.x 和 3.x 双代码库的维护,重新引入了对 unicode 旧字面值(u'value')的支持。有关更多信息,请参阅 PEP 414

前缀中带有 'f''F' 的字符串字面值是一个格式化字符串字面值;请参阅 f-字符串'f' 可以与 'r' 组合使用,但不能与 'b''u' 组合使用,因此可以使用原始格式化字符串,但不能使用格式化字节字面值。

在三引号字面值中,允许使用未转义的换行符和引号(并保留),但一行中三个未转义的引号会终止字面值。(“引号”是用于打开字面值的字符,即 '"。)

2.4.1.1. 转义序列

除非存在 'r''R' 前缀,否则字符串和字节字面值中的转义序列将根据与标准 C 使用的规则相似的规则进行解释。识别的转义序列是

转义序列

含义

备注

\<换行符>

反斜杠和换行符被忽略

(1)

\\

反斜杠 (\)

\'

单引号 (')

\"

双引号 (")

\a

ASCII 响铃 (BEL)

\b

ASCII 退格 (BS)

\f

ASCII 换页 (FF)

\n

ASCII 换行 (LF)

\r

ASCII 回车 (CR)

\t

ASCII 水平制表符 (TAB)

\v

ASCII 垂直制表符 (VT)

\ooo

八进制值为 ooo 的字符

(2,4)

\xhh

十六进制值为 hh 的字符

(3,4)

仅在字符串字面值中识别的转义序列有

转义序列

含义

备注

\N{name}

Unicode 数据库中名为 name 的字符

(5)

\uxxxx

16 位十六进制值为 xxxx 的字符

(6)

\Uxxxxxxxx

32 位十六进制值为 xxxxxxxx 的字符

(7)

备注

  1. 可以在行末添加反斜杠以忽略换行符

    >>> 'This string will not include \
    ... backslashes or newline characters.'
    'This string will not include backslashes or newline characters.'
    

    可以使用三引号字符串或圆括号和字符串字面值拼接来实现相同的结果。

  2. 与标准 C 语言一样,最多接受三个八进制数字。

    3.11 版本更改: 大于 0o377 的八进制转义会产生一个 DeprecationWarning

    3.12 版本更改: 大于 0o377 的八进制转义会产生一个 SyntaxWarning。在未来的 Python 版本中,它们最终会变成 SyntaxError

  3. 与标准 C 语言不同,必须正好是两位十六进制数字。

  4. 在字节字面值中,十六进制和八进制转义表示具有给定值的字节。在字符串字面值中,这些转义表示具有给定值的 Unicode 字符。

  5. 3.3 版本更改: 添加了对名称别名 [1] 的支持。

  6. 必须正好是四位十六进制数字。

  7. 任何 Unicode 字符都可以用这种方式编码。必须正好是八位十六进制数字。

与标准 C 语言不同,所有无法识别的转义序列都会保留在字符串中,不会更改,即反斜杠会保留在结果中。(此行为在调试时很有用:如果转义序列输入错误,则更容易识别出损坏的输出。)还需要注意的是,仅在字符串字面值中识别的转义序列属于字节字面值中无法识别的转义序列的类别。

3.6 版本更改: 无法识别的转义序列会产生一个 DeprecationWarning

3.12 版本更改: 无法识别的转义序列会产生一个 SyntaxWarning。在未来的 Python 版本中,它们最终会变成 SyntaxError

即使在原始字面值中,引号也可以用反斜杠转义,但反斜杠会保留在结果中;例如,r"\"" 是一个有效的字符串字面值,由两个字符组成:一个反斜杠和一个双引号;r"\" 不是有效的字符串字面值(即使是原始字符串也不能以奇数个反斜杠结尾)。具体而言,原始字面值不能以单个反斜杠结尾(因为反斜杠会转义后面的引号字符)。另请注意,后跟换行符的单个反斜杠会被解释为字面值的一部分,而不是行继续符。

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. 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.7 版本更改: 在 Python 3.7 之前,由于实现问题,在格式化字符串字面值中的表达式中不允许使用 await 表达式和包含 async for 子句的推导式。

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.4.4. 数值字面量

有三种类型的数值字面量:整数、浮点数和虚数。没有复数字面量(复数可以通过将实数和虚数相加形成)。

请注意,数值字面量不包括符号;像 -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"

除了可用内存中可以存储的内容外,整数字面量的长度没有限制。

下划线在确定字面量的数值时会被忽略。它们可以用于对数字进行分组,以增强可读性。一个下划线可以出现在数字之间,以及像 0x 这样的基数说明符之后。

请注意,非零十进制数中的前导零是不允许的。这是为了与 C 风格的八进制字面量进行消除歧义,Python 在 3.0 版本之前使用过这种字面量。

一些整数字面量的示例

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

在 3.6 版本中更改: 现在允许在字面量中使用下划线进行分组。

2.4.6. 浮点数字面量

浮点数字面量由以下词法定义描述

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

请注意,整数部分和指数部分始终使用基数 10 进行解释。例如,077e010 是合法的,并表示与 77e10 相同的数字。浮点数字面量的允许范围取决于具体实现。与整数字面量一样,支持使用下划线进行数字分组。

一些浮点数字面量的示例

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

在 3.6 版本中更改: 现在允许在字面量中使用下划线进行分组。

2.4.7. 虚数字面量

虚数字面量由以下词法定义描述

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

虚数字面量产生一个实部为 0.0 的复数。复数表示为一对浮点数,并且对其范围有相同的限制。要创建一个具有非零实部的复数,请将其添加一个浮点数,例如 (3+4j)。一些虚数字面量的示例

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

2.5. 运算符

以下标记是运算符

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

2.6. 分隔符

以下标记在语法中用作分隔符

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

句点也可以出现在浮点数和虚数字面量中。三个句点的序列作为省略号字面量具有特殊含义。列表的后半部分,即增强赋值运算符,在词法上用作分隔符,但也会执行操作。

以下可打印的 ASCII 字符作为其他标记的一部分具有特殊含义,或者对词法分析器具有其他重要意义

'       "       #       \

以下可打印的 ASCII 字符在 Python 中未使用。它们出现在字符串字面量和注释之外是无条件错误

$       ?       `

脚注