上下文在搞ios的时候就曾碰到过,但那时候并没有详细的了解,在python中看到后,有些忍不住了,于是看了几篇文章,过来做个总结.
这里只不过是个总结,如果想要学习推荐这两篇文章,写的很详细
http://blog.jobbole.com/64175/
http://www.ibm.com/developerworks/cn/opensource/os-cn-pythonwith/#icomments 这一篇写的尤为详细
有上面两篇文章在,我就不再做总结了.个人认为已经写的很详细了。这里只列举两篇文章中我认为重要的部分。
1.with语法格式
with context_expression [as target(s)]:
with-body
这里context_expression返回的是一个上下文管理器对象.这个对象已经满足了上下文协议,也就是说这个对象已经有了__exit__()与__enter__()方法,其中如果使用了as,那么将会将__enter__()方法返回的值赋值给target(s)
2.with的执行流程
这是我觉着第二篇文章的精华部分
context_manager = context_expression
exit = type(context_manager).__exit__
value = type(context_manager).__enter__(context_manager)
exc = True # True 表示正常执行,即便有异常也忽略;False 表示重新抛出异常,需要对异常进行处理
try:
try:
target = value # 如果使用了 as 子句
with-body # 执行 with-body
except:
# 执行过程中有异常发生
exc = False
# 如果 __exit__ 返回 True,则异常被忽略;如果返回 False,则重新抛出异常
# 由外层代码对异常进行处理
if not exit(context_manager, *sys.exc_info()):
raise
finally:
# 正常退出,或者通过 statement-body 中的 break/continue/return 语句退出
# 或者忽略异常退出
if exc:
exit(context_manager, None, None, None)
# 缺省返回 None,None 在布尔上下文中看做是 False
1.通过context_expression创建上下文管理器context_manager
2.检查__exit__方法,检查__enter__方法,如果都设置exc为True标记正常执行。这里有两个很有意思的地方,1>如果标记为True表示即使有错误也继续执行.2>在with中会先检查是否有__exit__方法
3.执行__enter__方法,如果with中有as则返回__enter__返回值
4.执行with-body,也即是with的代码块
5.这是核心步骤,通过代码我们也可以看出,不论有没有错误都会执行__exit__方法,却别就在于,如果没有异常,则以 None 作为参数调用 __exit__(None, None, None) .如果执行过程中出现异常,则使用 sys.exc_info 得到的异常信息为参数调用 __exit__(exc_type, exc_value, exc_traceback)
6.出现异常时,如果 exit(type, value, traceback) 返回 False,则会重新抛出异常,让with 之外的语句逻辑来处理异常,这也是通用做法;如果返回 True,则忽略异常,不再对异常进行处理.
3.自定义上下文管理器
class DummyResource:
def __init__(self, tag):
self.tag = tag
print 'Resource [%s]' % tag
def __enter__(self):
print '[Enter %s]: Allocate resource.' % self.tag
return self # 可以返回不同的对象
def __exit__(self, exc_type, exc_value, exc_tb):
print '[Exit %s]: Free resource.' % self.tag
if exc_tb is None:
print '[Exit %s]: Exited without exception.' % self.tag
else:
print '[Exit %s]: Exited with exception raised.' % self.tag
return False # 可以省略,缺省的None也是被看做是False
这个例子也很是经典。
__enter__方法并没有什么要研究的
关键在于__exit__方法
首先,不管是否有异常需先释放资源,然后,通过with的执行流程我们知道,如果没有报错exc_type,exc_value,exc_tb都应该是None,于是在__exit__方法中判断exc_tb是否为None,如果为None则说明正确执行或者是忽略错误,由于with中exc默认为True所以无需返回,如果不为None则说明要抛出异常,需返回False.
其实到这里就差不多算是了解上下文与with使用了.不过两篇文章都介绍了contextlib的使用.还是推荐各位看一下第二篇。
写道这里大家可能会费解,为什么会推荐第一篇。因为我觉着第一篇有这么一句话写的很好。
上下文管理器的任务是 —— 代码块执行前准备,代码块执行后收拾。
感谢收看,欢迎拍砖
网友评论