本来我们这个应该是和前面的with语句放在一块的,但是我想多写一篇,目的就是为了突出使用contextlib这个模块以后,我们的上下文管理器简化了很多。

我们还是先来看一段代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import contextlib


@contextlib.contextmanager
def file_open(file_name):
print("file open") # 此处代码就相当于之前的enter魔法函数实现的代码
yield {} # 必须是yield一个生成器,可以没有{},但是yield关键词必须有
print("file end") # 此处代码就相当于之前的exit魔法函数实现的代码


with file_open("envse.txt")as file_read:
print("file is reading")

# 输出结果:
file open
file is reading
file end

这是不是和我们前面的输出很相似,是的,这就是contextlib的好处,而且它可以把我们这个函数包装成一个上下文管理器对象,里面利用了我们生成器的一些特性。我们现在就是要搞清楚里面为什么是生成器,最好的方法就是直接阅读源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

def contextmanager(func):
"""@contextmanager decorator.

Typical usage:

@contextmanager
def some_generator(<arguments>):
<setup>
try:
yield <value>
finally:
<cleanup>

This makes this:

with some_generator(<arguments>) as <variable>:
<body>

equivalent to this:

<setup>
try:
<variable> = <value>
<body>
finally:
<cleanup>
"""

看到没有,这个函数的作用就是:

1
2
with some_generator(<arguments>) as <variable>:
<body>

所以我们刚才强调为什么必须是生成器的原因就在这里:some_generator,所以没事可以多看源码,可以提高自身能力。

参考文章:浅谈 Python 的 with 语句