Python 现代开发学习笔记

(七)文件的 with 与生成器式上下文

1. 转换失败后文件仍然关闭

# 整数转换出错时先离开文件上下文,再进入外面的 except。
from pathlib import Path

path = Path("bad-minutes.txt")
path.write_text("很多\n", encoding="utf-8")
try:
    with path.open(encoding="utf-8") as stream:
        minutes = int(stream.readline())
except ValueError:
    print("文件关闭", stream.closed)

得到 文件关闭 True。with 把文件使用范围与关闭动作放在同一层缩进关系中;文件打开本身失败时,主体没有开始,外层则会收到相应的打开错误。文件读写

2. 用 contextmanager 包装同一套进入退出动作

上一章手写了 __enter__ 和 __exit__。标准库还提供了把一个生成器函数变成上下文管理器的装饰器:

# yield 前建立资源,yield 交出资源,finally 在离开上下文时关闭它。
from contextlib import contextmanager
from pathlib import Path


@contextmanager
def open_utf8(path):
    stream = path.open(encoding="utf-8")
    print("打开")
    try:
        yield stream
    finally:
        stream.close()
        print("关闭")


path = Path("context.txt")
path.write_text("Python", encoding="utf-8")
with open_utf8(path) as stream:
    print(stream.read())

输出“打开”“Python”“关闭”。这次 yield 用来交出上下文主体使用的对象:进入时运行到这里并暂停,离开时恢复,完成 finally。主体的异常也会被送回这个暂停位置,再经过收尾向外传播。

生成器式上下文从进入到恢复收尾的执行位置

这里的上下文生成器交出一次资源,主体只运行一次;它与前一章可连续交出很多记录的数据生成器承担不同任务。contextmanager

笔记正文与全部题解 · Ctrl / ⌘ K