Python: 上下文管理器

在看flask的时候,接触到Flask的两个上下文对象,于是补了一下自己Python上下文方面的知识,记录在此。

前言

大佬们大概是嫌弃如下的代码太丑了:

1
2
3
4
5
6
7
try:
f = open('somefile''r+')
pass
except Exception as e:
print(e)
finally:
f.close()

于是,大佬们在2.5版本的Python中增加了with语句和上下文管理器。于是,经典的文件操作出现了:

1
2
with open('somefile', 'r+') as f:
pass

如此一来,代码量瞬间减少一截,而且更pythonic了。

理解

上下文管理器:一个实现了enter(self)和exit(self, exc_type, exc_valye, traceback)方法的类。

写下一份demo奉上:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class MyData():
def __enter__(self):
print('进入数据对象')
return self

def __exit__(self, exc_type, exc_value, traceback):
print('即将退出数据对象')
if traceback:
print('有异常,可以在这里处理掉')
else:
print('没有异常,ok')
return True

def get(self):
print('获取数据对象中的数据的方法')

try:
with MyData() as data:
data.get()
except Exception as e:
pass

with语句处理了一个上下文管理器实例,as后的data,其实是enter方法返回的内容,如果你想把这个方法返回的self改为其他内容,例如字符串‘qyy’,那么
data就是字符串qyy。

于是,可以执行data.get()方法。

关于异常的问题,我的代码中使用了try…except…语句,但是就算with下存在类似1/0等等能引发异常的代码,最后也不会执行except下的代码。

原因在于,即将退出数据对象的方法:exit

这个方法返回值是布尔值,默认为False,如果返回True,则代表我自己在这个方法内处理异常,不用外部代码操心异常问题了。

外部也就捕捉不到1/0异常了。

当然,一般是不写返回值,默认返回False,除非有特殊需求,另外,exit方法必须接受四个参数,如上我写了,接受了异常类型,值和traceback。

最后

感觉Python的灵活性体现出来了,哎,又熬夜了。
别人写的代码 vs 自己写的代码。

ps:需要深入更多python的高阶语法。我的代码简直就是SHI。