上下文管理的作用:
1.操作(创建/获取/释放)资源;
2.处理异常;
上下文管理的好处:
1.提高代码的复用率;
2.提高代码的优雅度;
3.提高代码的可读性;
好,带着上下文管理器的好处和作用进入正题…
什么是上下文管理器: 上下文管理器是指在一段代码执行之前执行另一段代码,用于一些预处理工作;执行之后再执行另一段代码,用于一些清理工作。可以理解为一个助理、管家,你在做什么事情之前他们会帮你安排好一切和之后的善后。
在平时敲代码过程中我们经常用到下面这段代码:
with open('test.txt', 'rb') as f:
print f.readlines()
没错上下文管理器的基础语法就是:
with ... as ...:
处理代码块
1.上下文表达式:with open(‘test.txt’) as f:;
2.上下文管理器:open(‘test.txt’);
3. f 是上下文表达式返回的资源对象;
在实现上下文管理之前我们还要知道上下文管理器之间的协议:
简单来说就是在类里面实现了__enter__和__exit__的方法,enter负责获取、连接资源,然后返回给处理代码块进行处理,最后的释放资源、处理异常都交由exit方法处理。
class Resource():
def __enter__(self):
print("获取资源......")
return self
def __exit__(self, exc_type, exc_val, exc_tb):
print("exc_type:%s" % exc_type)
print("exc_val:%s" % exc_val)
print("exc_tb:%s" % exc_tb)
print('释放资源......')
# return True
with Resource() as res:
a = 1 / 0
结果:
这里提一下exit里面的return和携带的三个参数:
return:为True就相当于告诉 Python解释器,这个异常我们已经捕获了,不需要再往外抛了(这就是with打开文件失败也不会报错的原因),默认是False。
exc_type:异常类型
exc_val:异常值
exc_tb:异常的错误栈信息
理解上面的所有之后,来模拟实现下文件的操作就对上下文管理器的作用和好处一目了然了。
正常操作文件:
file = open("text.txt", "r")
try:
file.read()
except Exception as exc:
print(exc)
finally:
file.close()
file = open("text.txt", "w")
try:
file.write("aaa")
except Exception as exc:
print(exc)
finally:
file.close()
我们要去捕获异常处理异常最后都要关闭文件,这样是不是很麻烦。那接下来就手动实现下上下文管理器,并操作文件的读写功能:
类的实现:
class OPEN():
def __init__(self, path, mode="r"):
self.path = path
self.mode = mode
def __enter__(self):
self.file = open(self.path, mode=self.mode)
return self.file
def read(self):
self.file.read()
def write(self, content):
self.file.write(content)
def __exit__(self, exc_type, exc_val, exc_tb):
self.file.close()
return True
file = open("./text.txt")
print(file)
with OPEN("./text.txt", "r") as f:
print(f)
f.read()
with OPEN("./text.txt", "w") as f:
print(f)
f.write("123")
如果只是要实现一个简单的功能,写一个类未免有点过于繁杂,如果能用一个函数就能解决掉干嘛非要一个类呢?
函数实现:
import contextlib
@contextlib.contextmanager
def OPEN(path, mode):
# __enter__方法
file_handler = open(path, mode)
try:
yield file_handler
except Exception as exc:
print(exc)
finally:
# __exit__方法
file_handler.close()
return
with OPEN('text.txt', 'w') as f:
f.write("hhh")
with OPEN('text.txt', 'r') as f:
print(f.read())
只要给函数加上contextlib.contextmanager装饰器就可以变成一个上下文管理器,就可以使用with调用了。
总结: 可以看出来主代码处只负责对返回的数据进行处理,而所有的文件打开、关闭操作和异常的处理都交由OPEN函数或类去实现,这样我们操作文件的时候就不用每次去打开、关闭文件,遇到异常还要进行捕获处理。所以才会用管家、助手来比喻最合适不过了,我只要告诉管家我要什么文件,管家就会帮我们找到文件打开等待处理,如果发现文件内容不对是不是管家开始到处查看哪里出了问题,并关闭文件收走。