if 语句之外的 else 块
这个语言特性不是什么秘密,但却没有得到重视:else 子句不仅能在 if 语句中使用,还能在 for、while 和 try 语句中使用。
else 子句的行为如下:
在 for 中 :仅当 for 循环运行完毕时(即 for 循环没有被 break 语句中止) 才运行 else 块。
在 while 中:仅当 while 循环因为条件为假值而退出时(即 while 循环没有被 break 语句中止)才运行 else 块。
在 try 中:仅当 try 块中没有异常抛出时才运行 else 块。
在所有情况下,如果异常或者 return、break 或 continue 语句导致控制权跳到了复合语句的主块之外,else 子句也会被跳过。
5.2 上下文管理器和 with 块
上下文管理器对象存在的目的是管理 with 语句,就像迭代器的存在是为了管理 for 语句一样。
with 语句的目的是简化 try/finally 模式。这种模式用于保证一段代码运行完毕后执行某项操作,即便那段代码由于异常、return 语句或 sys.exit() 调用而中止,也会执行指定的操作。finally 子句中的代码通常用于释放重要的资源,或者还原临时变更的状态。
# ⚠️ 执行 with 后面的表达式得到的结果是上下文管理器对象,
# 不过,把值绑定到目标变量 fp 上(as 子句)是在上下文管理器对象上调用 __enter__ 方法的结果。
# 1. 先执行表达式 open,打开文件对象,with 调用文件对象的 __enter__ 方法,然后将变量名 fp 绑定到 open 打开的文件对象上。
with open('mirror.py') as fp:
src = fp.read(60) # 从 fp 中获取数据
# 2. 离开 with 代码块,调用文件对象的 __exit__ 方法
len(src) # 60
# fp 变量仍可以使用
print(fp) # <_io.TextIOWrapper name='mirror.py' mode='r' encoding='UTF-8'>
# 可以读取 fp 对象的属性
print(fp.closed, fp.encoding) # (True, 'UTF-8')
# 3. 离开 with 代码块后,不能在 fp 上执行 I/O 操作,因为在 with 块的末尾,调用 TextIOWrapper.__exit__ 方法把文件关闭了。
fp.read(60)
# Traceback (most recent call last):
# File "<stdin>", line 1, in <module> ValueError: I/O operation on closed file.