上下文管理协议
实现了enter和exit这两个上下文管理器协议
with语句的执行原理
- 执行 context_exp 以获取上下文管理器
- 加载上下文管理器的 exit() 方法以备稍后调用
- 调用上下文管理器的 enter() 方法
- 如果有 as var 从句,则将 enter() 方法的返回值赋给 var
- 执行子代码块 with_suit
- 调用上下文管理器的 exit() 方法,如果 with_suit 的退出是由异常引发的,那么该异常的 type、value 和 traceback 会作为参数传给 exit(),否则传三个 None
- 如果 with_suit 的退出由异常引发,并且 exit() 的返回值等于 False,那么这个异常将被重新引发一次;如果 exit() 的返回值等于 True,那么这个异常就被无视掉,继续执行后面的代码
上下文管理器工具
Python提供了一个模块用于实现更函数式的上下文管理器用法。
contextlib.contextmanager
contextlib.contextmanager 是一个装饰器,它可以用来装饰被 yield 语句分割成两部分的函数,以此进行上下文管理。任何在yield之前的内容都可以看做在代码块执行前的操作,而任何yield之后的操作都可以看做是代码块结束后要做的操作。如果希望在上下文管理器中使用 “as” 关键字,那么就用 yield 返回你需要的值,它将通过 as 关键字赋值给新的变量。
使用 contextlib.contextmanager 时,可以大致套用如下的框架:
1 | from contextlib import contextmanager |
1 | import contextlib |
使用contextlib 定义一个上下文管理器函数,通过with语句,database调用生成一个上下文管理器,然后调用函数隐式的enter方法,并将结果通yield返回。最后退出上下文环境的时候,在excepit代码块中执行了exit方法。
contextlib.closing
contextlib.closing 方法在语句块结束后调用对象的 close 方法。1
2
3
4
5
6from contextlib import closing
import urllib
with closing(urllib.urlopen('http://www.python.org')) as page:
for line in page:
print line
contextlib.nested
contextlib.nested 方法用于替换嵌套的 with 语句。例如,有两个文件,一个读一个写,即进行拷贝。以下是不提倡的用法:
1 | with open('toReadFile', 'r') as reader: |
这里可以用 contextlib.nested 进行优化:1
2
3with contextlib.nested(open('fileToRead.txt', 'r'), \
open('fileToWrite.txt', 'w')) as (reader, writer):
writer.write(reader.read())