# 5.2 Python 语言规范

CPython 源码中包含了 Python 语言的定义，其作为参考规范供所有 Python 解释器使用。

此规范使用了人机可读的文件格式。文档内是对 Python 语言的详细解释，概述了允许的内容以及每个语句的行为。

### 语言说明文档

`Doc/reference` 目录包含了 Python 语言特性的介绍。

此目录中有你要了解的整个语言、结构体和关键词的文件：

图片文字翻译：

compound\_stmts.rst：if、while、for 和函数定义等复合语句

datamodel.rst：对象、值和类型

executionmodel.rst：Python 程序的结构

expressions.rst：Python 表达式的元素

grammar.rst：Python 的核心语法（引用 `Grammar/Grammar`）

import.rst：import 系统

index.rst：语言参考索引

introduction.rst：参考文档介绍

lexical\_analysis.rst：词法结构，如行、缩进、单词符号和关键字

simple\_stmts.rst：assert、import、return 和 yield 等简单语句

toplevel\_components.rst：说明执行 Python 的方法，如脚本和模块

### 示例

在 `Doc/reference/compound_stmts.rst` 中，你可以看见一个定义 `with` 语句的简单例子。

`with` 语句有很多用法，最简单的用法是上下文管理的实例化和嵌套代码块：

```python
with x():
    ...
```

你可以使用 `as` 关键词将结果赋值给变量：

```python
with x() as y:
    ...
```

你还可以使用逗号将上下文管理器连接起来：

```python
with x() as y, z() as jk:
    ...
```

此文档包含了用户可读的语言规范，而机器可读的规范位于`Grammar/python.gram` 中。

### 语法文件

Python 语法文件使用解析表达式语法规范。在语法文件中，你可以使用如下符号：

* \* 用于零次或多次重复；
* \+ 用于一次或多次重复；
* \[] 用于可选部分；
* \| 用于可选择项；
* () 用于定义优先级。

举一个实例的例子来说明，如果让你定义一杯咖啡，你会怎么来定义：

* 它一定有一个杯子；
* 它必须包含一杯及以上的浓咖啡；
* 它可以有牛奶，但此项是可选择的；
* 它可以有水，但此项是可选择的；
* 如果它包含牛奶，那么牛奶可以是多种多样的，如：全脂牛奶，脱脂牛奶以及豆奶。

用 PEG 来定义一杯咖啡，一份咖啡订单看起来是这样的：

![](https://1029588898-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FJhewUmzI3BNeGgeFH9Rv%2Fuploads%2Fgit-blob-7e19a44536d89a1761febc6116ec0715331d3fca%2F%E5%9B%BE5.2.2%20%E7%94%A8EBNF%E5%AE%9A%E4%B9%89%E4%B8%80%E6%9D%AF%E5%92%96%E5%95%A1.png?alt=media)

{% hint style="info" %}
**参见**

CPython 3.9 的源代码有两个语法文件。一种传统语法是用一个被称为 BNF 范式的上下文无关文法所编写。 CPython 3.10 已经删除了 BNF 语法文件(Grammar/Grammar)。 BNF 不是 Python 语言特有的，许多其他语言也用 BNF 作为语法符号。
{% endhint %}

在本章节，你将使用铁路图来展示语法。下图是定义咖啡语句的铁路图。 ![](https://1029588898-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FJhewUmzI3BNeGgeFH9Rv%2Fuploads%2Fgit-blob-ccdcd79523a8259c8bd8daefa97233ed55399ed9%2F%E5%9B%BE5.2.3%20%E7%94%A8%E9%93%81%E8%B7%AF%E5%9B%BE%E6%9D%A5%E8%A1%A8%E7%A4%BA%E4%B8%80%E6%9D%AF%E5%92%96%E5%95%A1%E5%AE%9A%E4%B9%89%E8%BF%87%E7%A8%8B.png?alt=media)

在铁路图中，每个可能的组合都必须要从左到右排成一行。其中可选的语句可以被绕过，而一些语句可以形成循环。

![](https://1029588898-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FJhewUmzI3BNeGgeFH9Rv%2Fuploads%2Fgit-blob-5dbea11ee3b0716f5dd45ddee3b54ab2538f6075%2F%E5%9B%BE5.2.4%20with%E8%A1%A8%E8%BE%BE%E5%BC%8F%E7%9A%84%E5%AE%9A%E4%B9%89.png?alt=media)

## 一个例子：while 语句

`while` 语句有多种形式。最简单的形式包含了一个表达式，然后是一个 : 终结符号以及一个代码块：

```
while finished == True:
    do_things()
```

或者，你可以使用一个赋值表达式，它在语法中被称为 `named_expression`。这是 Python 3.8 的新增特性：

```
while letters := read(document, 10):
    print(letters)
```

此外，`while` 语句后面还可以跟一个 `else` 语句和代码块。

```
while item := next(iterable):
    print(item)
    else:
        print("Iterable is empty")
```

如果你在语法文件中搜索 `while_stmt`，则会看到如下定义：

```
while_stmt[stmt_ty]:
| 'while' a=named_expression ':' b=block c=[else_block] ...
```

引号中的任何内容都是字符串文字，被称为**终结符号**。 终结符号用于识别关键字。

这两行定义还引用了另外两个定义：

1. **block** 是指包含一个及以上语句的代码块；
2. **named\_expression** 指的是一个简单表达式或者一个赋值表达式。

用铁路图来展示，`while` 语句如下所示：

图片不翻译

作为一个更加复杂的案例，`try` 语句在语法中的定义如下所示：

图片不翻译

`try` 语句有有两种用法：

1. `try` 只有一个 `finally` 语句；
2. `try` 有一个或多个 `except` 从句，后面跟一个可选的 `else` , 然后是一个可选的 `finally`。

用铁路图来展示，如下图所示：

图片不翻译

`try` 语句是一个更加复杂的优秀示例。

如果你想详细了解 Python 语言，那就通读定义在 `Grammar/python.gram` 中的语法。
