Python 3 文档(简体中文) 3.2.2 documentation

Version: 3.2.2
1. 简介 << 2. 词法分析 (Source) >>3. 数据模型

2. 词法分析

一个 Python 程序由 **解析器**(parser) 读入, 输入解析器的是由 **词法分析器**(lexical analyzer) 生成的 **语言符号**(token) 流. 本章讨论词法分析器是如何把文件割成若干语言符号的.

Python 使用 Unicode code points作为程序文本, 源程序文件的编码可以通过声明显式地修改, 默认为UTF-8, 详见 PEP 3120. 如果无法解码源代码, 就会抛出 SyntaxError 异常.

2.1. 行结构

一个Python程序被分割成若干 **逻辑行**(logical lines).

2.1.1. 逻辑行

ining* rules.

逻辑行的结束以 NEWLINE(新行) 语言符号表示. 语句不能跨多个逻辑行边界, 除非语法上就允许 NEWLINE (例如,复合语句中的语句之间) 出现在语句里. 一个逻辑行由一个物理行, 或者使用显式/隐式 **行连接**(line joining) 规则连接的多个物理行构成.

2.1.2. 物理行

一个物理行是以一个 “断行符号序列” 结束的一个字符序列. 在源代码中, 任何标准平台的 “断行符号序列” 都可以使用: Unix风格为ASCII LF(换行)字符; Windows风格为ASCII字符序列CR LF(回车加换行); Macintosh风格为ASCII CR(回车)字符. 无论在什么平台上, 以上这三种形式都可以使用.

在嵌入 Python 时,传递给 Python API 的源代码字符串应该使用标准C的断行习惯 (\n 字符, 代表 ASCII LF, 是行终止符).

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 字节序标记 (byte-order mark): b'\xef\xbb\xbf' ,也会认为文件是以UTF-8编码的 (其他程序也支持这种方式,比如微软的 notepad).

如果声明了一种编码,那么这个编码必须是 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语言符号). 在语句进行交互式输入时, 对空行的处理可能不同, 这依赖于 “输入-计算-输出”(read-eval-print) 循环的实现方式. 在标准交互解释器中, 一个纯粹的空行 (即不包括任何东西, 甚至注释和空白) 才会结束多行语句.

2.1.8. 缩进

逻辑行的前导空白 (空格和制表符) 用于计算行的缩进层次, 缩进层次然后用于语句的分组.

首先, 制表符被转换成 (从左到右) 一至八个空格, 这样直到包括替换部分的字符总数达到八的倍数 (这是为了与UNIX的规则保持一致. 然后, 根据首个非空白字符前的空格总数计算行的缩进层次. “缩进” 是不能用反斜线跨物理行接续的. 只有反斜线之前的空白字符才用于确定缩进层次.

如果源文件混合使用了制表符和空格, 并且缩进的意义依赖于制表符的空格长度的话, 那么这种缩进会以不一致为原因被拒绝, 并会抛出 TabError 异常.

**跨平台兼容性注意: ** 由于在非UNIX平台上的文本编辑器特性, 在单个源文件里使用混合空格和制表符的缩进是不明智的. 另一个值得注意的地方是不同平台可能明确地限制了最大缩进层次.

换页符 (formfeed) 可以出现在行首, 但以上介绍的缩进计算过程会忽略它. 在行前置空白的其它位置上出现的换页符会导致未定义的行为 (例如, 它可能使空格数重置为零).

每种连续行缩进的层次都会产生语言符号INDENT和DEDENT, 这里使用了堆栈数据结构, 如下所述.

在未读入文件第一行之前, 压入(push) 内一个零, 它此后再也不会被 弹出(pop). 所有压入堆栈中的数字都从底部向顶部增长. 在每个逻辑行的开头处, 它的缩进层次与栈顶比较, 如果两者相等则什么也不会发生; 如果它大于栈顶, 将其压入栈中, 并产生一个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  (不一致的缩进)
a level popped off the stack.)

(事实上, 前三个错误是由解析器发现的. 仅仅最后一个错误是由词法分析器找到的 — return r 的缩进层次与弹出堆栈的数不匹配.)

2.1.9. 语言符号间的空白

除了位于在逻辑行开始处或者字符串当中, 空格, 制表符和进纸符这些空白字符可以等效地用于分隔语言符号 (token). 只在两个符号在连接后会有其它含义时才需要使用空白分割它们, 例如, ab是一个符号, 但a b是两个符号.

2.2. 其它语言符号

除了NEWLINE, INDENT 和 DEDENT外, 还有以下几类语言符号: 标识符, 关键字, 字面值, 运算符分隔符. 空白不是语言符号 (除了断行符, 如前所述), 但可以用于分隔语言符号. 如果在构造某语言符号可能存在歧义时, 就试图用尽量长的字符串 (从左至右读出的) 构造一个合法语言符号.

2.3. 标识符和关键字

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

下面介绍的 Python 标识符定义是在 Unicode standard annex UAX-31 的基础上加以修改而成的, 更多细节可以参考 PEP 3131.

在 ASCII 范围 (U+0001..U+007F) 内, 标识符的有效字符与 Python 2.x 相同: 大小写字母 (A-Z), 下划线, 以及不能作为标识符开始的数字 (0-9).

Python 3.0 引入了在ASCII范围之外额外字符 (参见 PEP 3131). 对于这些字符, 分类(classification) 可以使用 unicodedata 模块中的 Unicode Character Database.

标识符不限长度, 区分大小写.

identifier  ::=  id_start id_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>

以上 Unicode category code 的缩写是:

  • Lu - uppercase letters
  • Ll - lowercase letters
  • Lt - titlecase letters
  • Lm - modifier letters
  • Lo - other letters
  • Nl - letter numbers
  • Mn - nonspacing marks
  • Mc - spacing combining marks
  • Nd - decimal numbers
  • Pc - connector punctuations

在解析时, 所有标识符都被转换为 NFC 形式, 标识符的比较是基于NFC的.

可以在这里找到一篇非标准的HTML文件列出了所有Unicode 4.1中有效的标识符字符: http://www.dcl.hpi.uni-potsdam.de/home/loewis/table-3131.html.

2.3.1. 关键字

以下标识符用作保留字, 或者叫做语言的 关键字, 它们不能作为普通标识符使用, 而且它们必须按如下拼写严格书写:

False      class      finally    is         return
None       continue   for        lambda     try
True       def        from       nonlocal   while
and        del        global     not        with
as         elif       if         or         yield
assert     else       import     pass
break      except     in         raise

2.3.2. 保留的标识符类型

除了关键字, 某些类型的标识符也具有特殊含义, 这种标识符一般都以下划线开始或结束:

_*

from moduls import * 不会导入这些符号. 在交互式解释器中, 特殊标识符 _ 保存上次计算 (evaluation) 的结果, 这个符号在 builtins 模块之中. 在非交互方式时, _ 没有特殊含义, 而且是没有定义的. 参见 The import statement 节.

Note

名字 _ 通常用于国际化开发, 关于这个惯用法, 可以参考模块 gettext.

__*__
系统预定义的名字. 这种名字由解释器及其实现定义 (包括标准库). 目前定义的系统名字在 特殊方法名 和其他地方有所介绍. Python的未来版本可能会引入更多的这种名字. 对于*不*符合文档说明的 __*__ 名字的用法, 可能会在以后版本中在没有任何警告的前提下失败.
__*
类私有名字. 此类名字出现在类定义的上下文中. 为了避免基类与继承类的 “私有” 属性的名字冲突, 它们会被自动更名为其他名字 (mangled form). 参考 Identifiers (Names).

2.4. 字面值

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

2.4.1. 字符串与字节的字面值

字符串字面值由以下词法定义描述:

stringliteral   ::=  [stringprefix](shortstring | longstring)
stringprefix    ::=  "r" | "R"
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"
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, 参见 编码声明.

通俗地讲, 这两种字面值可以用单引号(')或双引号(")括住. 它们也可以用成对的三个单引号和双引号(这叫做 三重引用串), 反斜线(\)可以用于引用其它有特殊含义的字符, 例如新行符, 反斜线本身或者引用字符.

字节字面值一定要以 'b''B' 开始, 这会产生一个:bytes 类的实例, 而不是 str 的. 它只能包括ASCII字符, 数值等于或者超过128的字节必须用转义字符表达.

字符串和字节字面值都可以用 'u''U' 开头, 这样的字符串字面值叫作 原始串(raw strings), 其中不对反斜线作转义处理, 因此, 原始串中的 '\U''\u' 不会得到特殊处理.

在三重引用串中, 未转义新行和引用字符是允许的 (并且会被保留), 除非三个连续的引用字符结束了该串. (引用字符指用于开始字符串的字符, 如 '" )

如果没有使用 'r''R' 前缀, 转义序列就按就按类似标准C那样解释, 可接受的转义序列见下表:

只有字符串字面值才支持的转义字符有:

转义序列 含义 备注
\N{name} Character named name in the Unicode database  
\uxxxx Character with 16-bit hex value xxxx (4)
\Uxxxxxxxx Character with 32-bit hex value xxxxxxxx (5)

Notes:

  1. 与C标准相同, 最多只接受三个八进制数字.
  2. 不像C标准, 这里要求给全2个十六进制数字.
  3. 在字节字面值中, 十六进制和八进制转义字符都是指定一个字节的值. 在字符串字面值中, 这些转义字符指定的是一个Unicode字符的值.
  4. 任何构成部分 surrogate pair 的单独 code unit 都可以使用转义字符序列编码. 不像C标准, 这里要求给全4个十六进制数字.
  5. 任何Unicode字符都可以用这种方式编码, 但如果 Python 是按 16位 code unit 编译的话(默认), 这里要求写全8个十六进制数字.

与标准C不同, 所有不能解释的转义序列都会留在串不变, 即 反斜线也会留在串中 (这个行为在调试中特别有用: 如果有转义字符输错了, 可以很容易地判断出来). 但也要留意, 字节字面值并不接受那些只有字符串字面值内有效的转义序列.

即使在原始串中, 字符引用也可以使用反斜线转义, 但反斜线会保留在字符串中, 例如, 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. 数值型的字面值

有三种数值型字面值: 整数, 浮点数和虚数. 没有复数类型的字面值, 复数可以用一个实数加上一个虚数的方法构造.

注意数值型字面值并不包括正负号, 像 -1, 实际上是组合了一元运算符 ‘-‘ 和字面值 1 的一个表达式.

2.4.4. 整数字面值

整数字面值由以下词法定义描述:

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

除了可用内存的容量限制, 整数长度没有其他限制.

注意, 非零十进制数字中不允许用0作为前缀, 这种写法会与 C 语言风格的八进制字面值产生歧义 (用于3.0之前版本的Python).

整数字面值的一些例子:

7     2147483647                        0o177    0b100110111
3     79228162514264337593543950336     0o377    0x100000000
      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")

虚数是实部为零的复数. 复数由一对有着相同取值范围的浮点数表示. 为了创建一个非零实部的复数, 可以对它增加一个浮点数, 例如, (3+4j). 下面是一些例子:

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

2.5. 运算符

运算符包括以下语言符号:

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

2.6. 分隔符

以下符号用作语法上的分隔符:

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

句号可以出现在浮点数和虚数字面值中, 三个连续句号的序列是片断的省略写法. 在这个列表的后半部分, 即参数化赋值运算符, 它们在词法上是分隔符, 同时也执行运算.

以下 ASCII 可打印字符, 要么在作为其它语言符号的一部分时有特殊含义, 要么对于词法分析器具有特殊作用:

'       "       #       \

Python 不使用以下ASCII可打印字符, 当它们出现在注释和字符串字面值之外时就是非法的:

$       ?       `