with关键字在Python里很常用,用作为上下文管理。例如打开文件,他可以避免我们获取文件句柄后,忘记关闭导致文件句柄还留在内存中存在风险,他是如何做到了,后续分析。
with open('./python1.py', 'r') as f:
print(f.read())
例如给线程加锁。
lock = threading.RLock()
def job1():
global A, lock
lock.acquire()
for i in range(10):
A += 1
print('job1', A)
lock.release()
def job2():
global A, lock
with lock:
# print(lock.__dict__)
for i in range(10):
A += 10
print('job2', A)
with lock相当于在执行之前调用lock.acquire()加锁,在退出后调用lock.release()释放锁。
如果我们没有release()那job2就永远无法获得这把锁了。死锁。
class MyOpen:
def __init__(self, path, mode):
self._path = path
self._mode = mode
def __enter__(self):
self._handle = open(self._path, self._mode)
return self._handle
def __exit__(self, exc_type, exc_val, exc_tb):
print('游戏结束')
self._handle.close()
with MyOpen('./python1.py', 'r') as f:
print(f.read())
输出:
'''''''''''''''
main()
游戏结束
1. 上下文表达式:with open('test.txt') as f:
2. 上下文管理器:open('test.txt')
3. f 不是上下文管理器,应该是资源对象。
Myopen是一个上下文管理器。
with Myopen() as f 是上下文表达式。
with 会在进入时调用__enter__方法,在退出时调用__exit__方法。
这就是上下文管理协议的一个强大之处,异常可以在__exit__ 进行捕获并由你自己决定如何处理,是抛出呢还是在这里就解决了。在__exit__ 里返回 True(没有return 就默认为 return False),就相当于告诉 Python解释器,这个异常我们已经捕获了,不需要再往外抛了。
@contextlib.contextmanager
def open_func(path, mode):
# __enter__方法
print('open file:', path, 'in __enter__')
file_handler = open(path, mode)
yield file_handler
# __exit__方法
print('close file:', path, 'in __exit__')
file_handler.close()
return
with open_func('./python1.py', 'r') as f:
print(f.read())
如果只是希望将普通函数变成上下文管理器,我们并不需要去写一个很重的类,只需要用装饰器@contextlib.contextmanager就行,这里注意的是第7行用的是一个yield关键字,也就是函数返回的对象一个生成器,这里的目的看上去非常容易,就是让程序运行到yield关键字停住,意味着__enter__方法的结束,并且保存此时的状态,等待下一次进行__next__方法去触发__exit__方法。
15行,打break