本参考手册描述 Python 的语法及“核心语义”,简洁但力图精准、完备,如需:

总目录

  1. 介绍 ✅
  2. 词法分析 ✅
  3. 数据模型 [50% ✅]
  4. 执行模型
  5. 导入系统
  6. 表达式
  7. 简单语句
  8. 复合语句
  9. 顶层组件
  10. 完整语法规范

1. 介绍

1.1. 实现

  • CPython:最常见常用的 C 语言实现,托管在 GitHub
  • Jython
  • Python for .NET
  • IronPython
  • PyPy:Python 实现的 Python,支持无堆栈和 JIT,官网PyPy

1.2. 记法说明

本手册采用不严格的 BNF 语法标记法,如:

name ::= lc_letter (lc_letter | "_")*  
lc_letter ::= "a"..."z"  
  • ::= 定义规则
  • | 表示可选,即“或”
  • * 表示前项重复0或多次
  • + 表示前项重复1到多次
  • [] 表示所包含项出现0或1次(即可有可无)
  • () 表示分组
  • "" 表示字符
  • (空格)仅表示分隔
  • ... 表示 ASCII 表中某范围内的所有符号

2. 词法分析

2.1. 行结构

Python 程序由一系列逻辑行组成;逻辑行以 NEWLINE 结尾由一个或多个通过连接规则连接在一起的物理行物理行行尾序列结尾。

注释:以 # 开头的物理行。

编码声明:Python 3.5 默认源码文件编码方式为 UTF-8;若需指定编码方式,可在头两行加入能被正则coding[=:]\s*([-\w.]+)捕捉的编码声明,若放在第二行,则第一行必须被注释,常用的声明方式为:

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

显式行连接

通过反斜杠 \ 可以显式连接物理行,但不能与注释符 # 同处一行;字面量中只有字符串可以使用反斜杠连接多行:

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

隐式行连接

圆括号(元组)、方括号(列表)、花括号(字典)的内部可以直接跨多个物理行而被隐式连接为一个逻辑行,且可以在每行结尾添加注释:

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

三引号的多行字符串形式也是一种隐式行连接,但注释行将失效。

缩进

逻辑行是通过开头的空白符(空格或制表符)数量来计算该行的缩进层级的。不要混用制表符和空格

通过 INDENTDEDENT 和栈结构来处理多行语法块。

2.2. 其它

除了 NEWLINEINDENTDEDENT 之外,还包括如下几类符号(Token):

  • 标识符
  • 关键字
  • 字面量
  • 操作符
  • 分隔符

空格只用于分隔符号,存在歧义时,取最长字符所代表的符号。

2.3. 标识符与关键字

标识符:ASCII 中的大小写字母,数字 0 到 9,下划线_,Python 3 引入 Unicode 字符也可合法。

关键字

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  

保留标识符

  • _*:下划线开头的变量在 from module import * 时不会被导入;_ 本身也是特殊标识符,在交互模式下用于表示上一次执行的结果,在非交互模式下,没有特殊含义,只用作占位符(如 for _ in range(n));
  • __*__:参考特殊方法名
  • __*:类中的私有属性名。

2.4. 字面量

字面量表示某些内置类型常量,即“所见即值”。

字符串与字节

stringliteral   ::=  [stringprefix](shortstring | longstring)  
stringprefix    ::=  "r" | "u" | "R" | "U"  
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>  

单、双引号包围的短字符串和三引号包围的多行长字符串(字节),均可以r""R""开头表示原始字符串,在这种情况下反斜杠\不再起到转义功能;以u""U""开头是为了表示 Unicode 字符,这在 Python 3 以后是没有必要的,只是为了兼容 2.x 以前的代码。

字符串可以通过如下形式跨行连接:

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

整数

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 的十进制整数前不能有 0。

浮点数

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

科学计数法中整数与指数都是十进制的。浮点数值的范围与具体实现相关。

虚数

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

复数

将实数与虚数相加。

2.5. 操作符

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

2.6. 分隔符

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

以下字符在字符串以外出现是非法的:

$       ?       `

”一切皆为对象”是 Python 人尽皆知的一个重要概念,因为对于 Python 来说,无论是程序还是数据,都是以对象形式来表示的。第3小节数据模型即描述了 Python 中不同对象的特征与继承关系等,因此这一小节也有助于理解 Python 语法背后的原理。

3. 数据模型

3.1. 对象,类型与值

  • 对象(Objects)是 Python 中对数据(Data)的抽象:Python 中所有数据都是通过对象或对象之间的关系来表示的。
  • 一切对象都有唯一不变的 ID,通过 is 可以比较两个对象的 ID 是否相同,也可以通过 id() 方法直接查看对象的 ID。
  • 一切对象都有不可变类型(Type),类型决定该对象所支持的方法以及可能拥有的值,可以通过 type() 方法查看对象的类型。
  • 一切对象都有值(Value),某些对象的值是可变的(mutable),另外一些则是不可变的(immutable),是否可变取决于其类型。
  • 容器对象(Container)包含对其它对象的引用,例如:元组、列表、字典;通常情况下我们讨论容器对象的值是指其真实值,只有在讨论可变性时才是指其对其它对象的引用。
l = [1, 2, 3]  
t = (l, 321)  
print("初始 t 值:", t)  
t[0].append(4)  
print("改动后的 t 值:", t)  
print("由于 t 中保存的实际上是对 l 的引用,因此 l 的值也被改变:",l)  
初始 t 值: ([1, 2, 3], 321)
改动后的 t 值: ([1, 2, 3, 4], 321)
由于 t 中保存的实际上是对 l 的引用,因此 l 的值也被改变: [1, 2, 3, 4]
  • 类型几乎影响对象的一切行为,包括对象的 ID:
# 对于不可变对象,创建新对象可能与已有相同值的对象拥有相同 ID
# (不同实现情况可能不同)
a = 2  
b = 2  
c = 1 + 1  
print(a is b and b is c)

# 但是对于可变对象,则新对象的 ID 一定不同
e = []  
f = []  
print(e is f)  
True
False

3.2. 类型继承关系

如上所述,Python 中一切皆为对象,而对象的类型至关重要。因此这一小节主要关于 Python 所有对象的继承关系及特性,如下图所示:

代码示例

  • 函数对象

  • 实例方法对象

Python, TLDR, 文档

- END -



侧栏导航