python上下文管理器和else块
目录
前言
- 本文讨论python中的流程控制特性,主要包括两个方面:
- with语句和上下文管理器,with语句会设置一个临时的上下文,交给上下文管理器控制,并且负责清理上下文。
- for while try 语句中的else子句
if语句之外的else块
for/else
- 只有当for循环运行完毕,即没有被break停止时,才运行else模块。如下例子,如果找到了banana,那么循环就会提前终止,则else子句不会执行。
![]()
try/else
- 仅当try块中没有异常抛出时才运行else块。如下例子,左边不用else子句,只有当dangerous_call不抛出异常的时候,after_call才会运行,但是这样代码逻辑不够清晰,于是可以改成右边。
![]()
while/else
- 仅当while循环执行完毕,即循环条件为False而正常退出循环时,才运行else块,若while循环被break语句中止则不运行else块。
上下文管理器对象和with块
上下文管理器对象存在目的
- 上下文管理器对象存在的目的是管理with语句,就像迭代器对象可以管理for语句一样。
with语句存在目的
- with语句存在目的是简化try/finally模式。try/finally模式保证在try块中代码运行完毕后执行finally模块中的操作,即使try块中的代码由于异常、return语句或sys.exit()调用而终止,也会执行finally模块中的操作。finally子句中的代码通常用于释放重要的资源,或还原临时变更的状态。
上下文管理器对象协议
- 上下文管理器协议包括__enter__和__exit__两个方法,只要实现了__enter__和__exit__这两个方法,就能作为with语句块中的上下文管理器对象使用。
- with语句开始运行时,会在上下文管理器对象上运行__enter__方法。
- with语句运行结束后,会在上下文管理器对象上调用__exit__方法,__exit__方法来扮演finally子句的角色。
with语句使用案例---确保关闭文件对象

- with语句后边应该跟上一个上下文管理器对象,即实现了__enter__和__exit__方法的对象,这里open()函数返回一个文件对象(属于TextTOWrapper类),文件对象实现了上下文管理器协议,其__enter__方法返回self。这里把__enter__方法的返回值绑定到fp上,即把文件对象本身绑定在fp上,谁让其__enter__方法返回self呢。
- 从fp中读取一些数据。
- fp变量仍然可用,即fp不是局部变量。与函数和模块不同,with块并没有定义新的作用域。
- 可以读取fp对象的属性。
- 但是不能在fp上执行I/O操作,因此with块末尾会自动调用文件对象的__exit__方法把文件关闭。这里需要注意,是调用文件对象的__exit__方法,而不是调用__enter__方法返回值的__exit__方法,虽然在这个例子中两个是同一个,因为__enter__返回self。
- with语句的as子句可选,但是对于open函数是必须有的,以便获取文件的引用。
@contextmanager把生成器函数变成上下文管理器
- @contextmanager装饰器在包contextlib中。
- @contextmanager装饰器可以装饰一个生成器对象,使其变成一个上下文管理器,不用去实现__enter__和__exit__方法。
- 这里的生成器对象是用于生成上下文管理的,不适用于迭代的,所以一般yield语句只执行一次,而不是用于迭代时候会产出很多元素。
- 在使用@contextmanager装饰的生成器中,yield语句的作用是把函数的定义体分为两部分:
- yield语句前面的所有代码在with块的开始,即解释器调用__enter__方法时执行,充当__enter__方法的函数体。
- yield语句后边的代码在with块结束时,即调用__exit__方法时执行,充当__exit__方法的函数体。


浙公网安备 33010602011771号