Python yield使用详解(二)
yield的第二部分主要是with模块的功能,即上下文管理器。我们可以用contextmanager
装饰器加上yield
语法代替传统的__enter__
,__exit__
魔法方法,让代码变得更Pythonic!
1. 上下文管理器和with块
1.1 with表达式
常见的with用法格式,控制代码块的进入/退出
:
1 |
|
1.2 定制你自己的上下文管理器
一个计时器的例子:
1 |
|
另外一个例子:临时文件夹
1 |
|
等等!!!,这里的yield outdir
是什么?
- 不是迭代
- 不是数据流
- 不是并发
- 那是什么???
2. 深入上下文管理器
现在可以对上面内容进行小结一下:
- 上下文对象存在的目的是管理
with
语句,就像迭代器的存在是为了管理for
语句 - with语句的目的是简化t
try/finally
模式,这种模式用于保证一段代码运行完毕后执行某项操作。即使那段代码由于异常,return
语句或sys.exit()
调用而终止,也会执行指定操作
上下文管理器的内部实现:
- 上下文管理器协议包含__enter__和__exit__两个方法,
with
语句还是运行时,会在上下文管理器对象上调用__enter__方法。with语句结束后,会在上下文管理器对象上调用__exit__方法,以此扮演finally子句的角色
实现模板
1 |
|
实例
1 |
|
3. 更简洁的一种选择:利用@contextmanager装饰器
1 |
|
3.1 contextmanager装饰器运行原理
下图:
- 思考剪刀处
yield
代码 - 将代码一分两半
- 每一半对应着上下文管理器协议
yield
是促成图中这一实现的魔法
这里有一个注意点:使用@contextmanager
装饰器时,要把yield语句放在try/finally
语句中,这是无法避免的,因为我们永远不知道上下文管理器的用户会在with中做什么(会引发一些python解释器能捕获到的错误)。
当然,想要你如果想要更加深入的了解@contextmanager
的内部代码实现,可以查看源代码,这里不展开了。
4. 总结
yield
表达式的另一个不同作用:上下文管理器- 常用来重新定制控制流
- 也可以用
@contextmanager
装饰器来代替__enter__和__exit__两个方法。优雅且实用,把三个不同的Python特性结合到一起: 函数装饰器,生成器和with
语句
本博客所有文章除特别声明外,均采用 CC BY-SA 3.0协议 。转载请注明出处!