上下文管理器最常用在需要管理类似文件,网络连接和锁这样的资源的程序中。这些资源的关键点在于他们必须显式地进行关闭或释放才能正确工作。
要编写一个上下文管理器,其背后的主要原则就是我们编写的代码需要包含在由with语句定义的代码块中。要让对象能够兼容with语句,需要实现__enter__()和__exit__()方法。
实现一个文件的上下文管理器
class File(object):
def __init__(self, file, mode):
self.file = file
self.mode = mode
def __enter__(self):
self.opened_file = open(self.file, self.mode)
return self.opened_file
def __exit__(self, type, value, traceback):
self.opened_file.close()
# 实现了__enter__()和__exit__()方法后,就能通过with语句进行上下文管理
with File('hello.txt', 'w') as f:
f.write('hello')
内部实现过程:
1、with语句先暂存了File类的__exit__方法,然后它调用File类的__enter__方法。
2、__enter__方法打开文件并返回给with语句,打开的文件句柄被传递给opened_file参数。
3、with语句调用之前暂存的__exit__方法,__exit__方法关闭了文件。
异常处理:
1、 它把异常的type,value和traceback传递给__exit__方法
2、 它让__exit__方法来处理异常
3、如果__exit__返回的是True,那么这个异常就被忽略。
4、如果__exit__返回的是True以外的任何东西,那么这个异常将被with语句抛出。
通过@contextmanager实现上下文管理器
利用contextlib模块中的@contextmanager装饰器,可以非常方便的编写一些小巧的上下文管理器函数。
from contextlib import contextmanager
@contextmanager
def file(file, mode):
file = open(file, mode)
try:
yield file
finally:
file.close()
# 使用
with file('hello.txt', 'w') as f:
f.write('hello world!')
在file()函数中,所有位于yield之前的代码会作为上下文管理器的__enter__()方法来执行,而所有位于yield之后的代码会作为__exit__()方法执行。如果有异常产生,则会在yield语句中抛出。
转自:https://www.jianshu.com/p/0f4e2babb85d
参考:https://www.cnblogs.com/sfencs-hcy/p/10125534.html
https://www.cnblogs.com/huchong/p/8268765.html