跳转到内容
新建笔记

Python 关键字:保留字、上下文管理与生成器

关键字属于 Python 语法,不能直接用作变量、函数或类的名字,例如不能写 class = 3。print、list 和 type 是内置名字;其中 type 在 Python 3.12 起还具有特定语法位置下的软关键字身份。不要把内置名字与保留关键字混为一谈,也应避免用变量覆盖常用内置函数。

关键字区分大小写:True 是关键字,true 是普通标识符。运行环境的实际清单可以直接查询:

import keyword
import sys
print(sys.version_info[:3])
print(keyword.kwlist)
print(keyword.softkwlist) # Python 3.9 起提供
assert keyword.iskeyword("class")
assert not keyword.iskeyword("print")

下面按用途整理 Python 3.11 的 35 个关键字;同一个关键字可能参与多种语法。

用途关键字
常量False、None、True
条件、循环与控制流if、elif、else、for、while、break、continue、pass
逻辑、身份与成员测试and、or、not、is、in
定义、返回与生成器def、class、lambda、return、yield
异常和断言try、except、finally、raise、assert
导入、绑定与资源管理import、from、as、with
作用域和删除绑定global、nonlocal、del
异步语法async、await

软关键字只在某些语法位置有特殊意义。Python 3.10 引入模式匹配,其中 match、case 和作为通配模式的 _ 属于软关键字;这些名字在其他位置仍可作为普通标识符。Python 3.12 的 type 语句也使用软关键字。跨版本编写程序时,以目标解释器和对应版本文档为准。Python 词法规则、keyword 模块

with:管理一个上下文的进入和退出

跳转到“with:管理一个上下文的进入和退出”

with 调用上下文管理器的进入、退出方法。as 后的变量接收 __enter__() 的返回值,它未必就是管理器本身。成功进入上下文后,无论语句块正常结束还是发生 Python 异常,退出过程都会调用 __exit__();进程被强制终止等情况不属于这一保证。with 语句

下面用内存文本流演示关闭行为,不依赖磁盘文件:

from io import StringIO
stream = StringIO("第一行\n第二行\n")
with stream as reader:
assert reader.readline() == "第一行\n"
assert stream.closed

自定义上下文管理器可以记录进入与退出。__exit__() 返回真值会抑制语句块的异常;返回 False 或默认的 None 则不抑制。

events = []
class Session:
def __enter__(self):
events.append("enter")
return "session-value"
def __exit__(self, exc_type, exc_value, traceback):
events.append("exit")
return False
try:
with Session() as value:
assert value == "session-value"
raise ValueError("示例错误")
except ValueError:
events.append("caught")
assert events == ["enter", "exit", "caught"]

as:在特定语法中绑定名字

跳转到“as:在特定语法中绑定名字”

as 不能独立完成任意赋值。它的作用取决于所在语句:

语法绑定含义
import math as m将导入模块绑定为 m
from math import sqrt as root将导入对象绑定为 root
with manager as value将进入方法的返回值绑定为 value
except ValueError as error将当前异常绑定为 error;异常处理块结束时会清除此绑定
import math as m
from math import sqrt as root
assert m.floor(2.9) == 2
assert root(9) == 3

yield:生成一个值,然后暂停

跳转到“yield:生成一个值,然后暂停”

在普通 def 函数中出现 yield,会使该函数成为生成器函数。调用它先返回生成器对象;执行 next() 时才开始运行函数体,并在下一个 yield 暂停。再次调用 next() 会从暂停位置继续,局部状态得以保留。

def samples():
yield 10
yield 20
yield 30
iterator = samples()
assert next(iterator) == 10
assert next(iterator) == 20
assert list(iterator) == [30]
assert next(iterator, "结束") == "结束"

生成器是一次性迭代器,耗尽后不会自动回到开头。逐个产生数据可以避免一次建立完整结果列表,但如果函数内部本身创建了大列表,仍会占用相应内存。异步生成器和 yield from 有各自的规则,可再结合具体用途学习。

pass 是空语句,用于需要语句但暂时没有操作的位置;它不会跳过本轮循环。continue 才会转到下一轮。

with_pass = []
with_continue = []
for i in range(5):
if i == 2:
pass
with_pass.append(i)
for i in range(5):
if i == 2:
continue
with_continue.append(i)
assert with_pass == [0, 1, 2, 3, 4]
assert with_continue == [0, 1, 3, 4]

Python 3 的 range(5) 是表示整数范围的 range 对象,依次提供 0 到 4,并非已经创建了一个列表。上例的列表由 append() 构造。

  1. print 是否属于 keyword.kwlist?不是,它是内置函数名。
  2. with manager as value 中,value 必然等于 manager 吗?不必然,它是 __enter__() 的返回值。
  3. pass 会让循环漏掉一个值吗?不会,后续语句仍然执行。
  4. 生成器已经耗尽,再调用不带默认值的 next() 会怎样?引发 StopIteration。

本页代码在 Python 3.11.5 中逐段实际执行通过;Python 3.12 起的 type 语句说明依据官方文档,不属于该本地运行验证范围。