python语言基础-5 进阶语法-5.5 上下文管理协议(with语句)
声明:本内容非盈利性质,也不支持任何组织或个人将其用作盈利用途。本内容来源于参考书或网站,会尽量附上原文链接,并鼓励大家看原文。侵删。
5.5 上下文管理协议(with语句)(参考链接:https://blog.csdn.net/Ego_Bai/article/details/80873242)
5.5.1 with语句及其使用
有一些任务,可能事先需要设置,事后做清理工作。对于这种场景,Python的with语句提供了一种非常方便的处理方式。
其中一个很好的例子是文件处理,你需要获取一个文件句柄,从文件中读取数据,然后关闭文件句柄。
如果不用with语句,代码如下:
file = open("/tmp/foo.txt")
data = file.read()
file.close()
这里有两个问题:一是,可能忘记关闭文件句柄;二是,文件读取数据发生异常,没有进行任何处理。下面是处理异常的加强版本:
file = open("/tmp/foo.txt")
try:
data = file.read()
finally:
file.close()
这段代码运行良好,但是太冗长。这时候with便体现出了优势:不但有更优雅的语法,还可以很好的处理上下文环境产生的异常。下面是with版本的代码:
with open("/tmp/foo.txt") as file:
data = file.read()
在操作多线程时,也有很多相关对象是支持上下文管理协议的。如下:
with some_lock:
# do something...
# 上面的代码相当于
some_lock.acquire()
try:
# do something...
finally:
some_lock.release()
由此可见,with用来操作支持上下文管理协议的对象。
5.5.2 with是如何工作的(如何支持上下文管理协议)
一个对象要想支持上下文件管理协议,必须满足要求:对象必须有一个enter()方法,一个exit()方法。因为with语句的执行过程是:紧跟with后面的语句被求值后,返回对象的__enter__()
方法被调用,这个方法的返回值将被赋值给as后面的变量。当with后面的代码块全部被执行完之后,将调用前面返回对象的__exit()__
方法。
我们可以自定义一个对象并使用with。如下:
class Sample:
def __enter__(self):
print("in __enter__")
return "Foo"
def __exit__(self, exc_type, exc_val, exc_tb): # exc_type:错误的类型;exc_val:错误类型对应的值;exc_tb:代码中错误发生的位置
print("in __exit__")
def get_sample():
return Sample()
with get_sample() as sample:
print("Sample: " ,sample)
with语句是很常用的,因为有关文件流、进程、线程及协程的操作,大部分都是支持上下文件管理协议的,为了简洁语法我们可以多使用with。