经常我们在设计API的时候会有这样的需求:
(1)用户从某个管理器中获取一个资源
(2)用户使用这个资源
(3)在使用完之后,需要将这个资源还给管理器
一般情况下,我们需要做两个接口:
get,和return
这样子有一种风险就是,在写业务代码的时候,忘记了将资源还回去。。。
但是对于python而言,由于加上了上下文管理,就可以避免这种问题。。。而且对于API的设计而言,也更加的鲁棒。。。
也就是我们常见的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
上面就是with语句的执行流程,大体分为如下几个步骤:
(1)获取上下文管理器
(2)获取管理器的exit和enter方法
(3)调用enter方法,然后获取一个值,如果调用with的地方有as语句的话,需要进行赋值
(4)执行with语句的body部分代码
(5)检查异常,如果正常的话,调用exit。。。
其实,也就是python的with语句的执行为我们做好了这些上下文的管理。。。。
前面都说了一大堆的介绍,那么看一下该如何创建支持上下文管理的方法吧:
#-*-coding:utf-8-*-
__author__ = 'fjs'
import contextlib
@contextlib.contextmanager
def test():
try:
yield 1
except:
print "ooo"
raise
else:
print "ok"
try:
with test() as fjs:
print fjs
except:
print "error"
这里的关键是使用了上面的额注解。。。利用了python给好的工具。。。
其实这里还可以看到,定义的方法其实是一个生成器。。。这样,在yield返回之后,就可以做资源的回收工作了。。。嗯。。。还是挺好用的。。以后在设计API的时候就应该果断的用上。。。
@contextlib.contextmanager