在实际的编码过程中,有时有一些任务,需要事先做一些设置,事后做一些清理,这时就需要python with出场了,with能够对这样的需求进行一个比较优雅的处理,最常用的例子就是对访问文件的处理。
一般访问文件资源时我们会这样处理:
f = open(r'c:\test.txt', 'r')
data = f.read()
f.close()
这样写没有错,但是容易犯两个毛病:
- 如果在读写时出现异常而忘了异常处理。
- 忘了关闭文件句柄
以下的加强版本的写法:
f = open(r'c:\test.txt', 'r')
try:
data = f.read()
finally:
f.close()
以上的写法就可以避免因读取文件时异常的发生而没有关闭问题的处理了。代码长了一些。
但使用with有更优雅的写法:
with open(r'c:\test.txt', 'r') as f:
data = f.read()
with后面接的对象返回的结果赋值给f。此例当中open函数返回的文件对象赋值给了f.with会自已获取上下文件的异常信息。
with是如何做到的呢?
with后面返回的对象要求必须两__enter__()/exit()这两个方法,而文件对象f刚好是有这两个方法的,故应用自如。
在并发变成,处理多线程锁的场景是,也可以用with来做比如
def sub2():
global count, lock
if lock.acquire(1):
# acquire()是获取锁,acquire(1)返回获取锁的结果,成功获取到互斥锁为True,如果没有获取到互斥锁则返回False
tmp = count
time.sleep(0.001)
count = tmp + 1
time.sleep(0.1)
lock.release() # 一系列操作结束之后需要释放锁
def sub3():
global count, lock
with lock:
tmp = count
time.sleep(0.001)
count = tmp + 1
def verity(fun):
global count
thread_list = []
for i in range(100):
t = td.Thread(target=fun, args=())
t.start()
thread_list.append(t)
for j in thread_list:
j.join()
print(count)
if __name__ == '__main__':
count = 0
lock = td.Lock()
verity(sub3)