with语句会设置一个临时的上下文,交给上下文管理器对象控制,并且负责清理上下文。这么做能避免错误并减少样板代码。因此API更安全,而且易于使用。
if语句之外的else块
else子句不仅能在if语句中使用,还能在for,while和try语句中使用。
else子句的行为如下:
for:仅当for循环运行完毕时(即for循环没有被break语句终止)才运行else块
while:仅当while循环因为条件为假值而退出时(即while循环没有被break语句终止)才运行else模块
try:仅当try块中没有异常抛出时才运行else块。
在循环中使用else子句的方式如下述代码片段所示:
上下文管理器和with块
上下文管理对象存在的目的是管理with语句,就像迭代器的存在是为了管理for语句一样。
with语句的目的是简化try/finally模式。这种模式用于保证一段代码运行完毕后执行某项操作,即使那段代码由于异常、returnhuosys.exit()终止,finally子句中的代码通常用于释放重要的资源,或者还原临时变更的状态。
上下文管理器协议包含__enter__和__exit__两个方法。with语句开始运行时,会在上下文管理器对象上调用__enter__方法。with语句结束后,会在上下文管理器对象上调用__exit__方法。
1、fp绑定到打开的文件上,因为文件的__enter__方法返回self
2、在with块的末尾,调用TextIOWrapper.__exit__方法把文件关闭。
3、不管控制流程以哪种方式退出with块,都会在上下文管理器对象上调用__exit__方法,而不是在__enter__方法返回的对象上调用。
下例测试LookingGlass上下文管理器
下例是LookingGlass的实现
1、除了self之外,python调用__enter__方法时不传入其他参数。
2、把原来的sys.stdout.write方法保存在一个实例属性中,供后面使用。
3、为sys.stdout.write打猴子补丁,替换成自己编写的方法。
使用@contextmanager
@contextmanager装饰器能减少创建上下文管理器的样板代码量,因为不用编写一个完整的类,定义__enter__和__exit__方法,而只需实现有一个yield语句生成器,生成想让__enter__方法返回的值。
在使用@contextmanager装饰器的生成器中,yield语句的作用是把函数的定义体分成两部分:yield语句前面的所有代码在with块开始时执行,yield语句后面的代码在with块结束时执行。
下面举个例子:
1、使用yield关键字产出一个值,这个值会绑定到with语句中as子句的目标变量上。执行with块中的代码时,这个函数会在这一点暂停。
2、控制权一旦跳出with块,继续执行yield语句之后的代码,这里是恢复成原来的sys.stdout.write方法。