contextmanager 位于contextlib 里面,用于创建使用上下文管理器 的函数
使用
from contextlib import contextmanager
@contextmanager
def test(value):
new_number = 1 #1 do something
yield new_number #2
print('finish:',value + new_number) #3 do something
contextmanager 修饰的函数可以分为三个部分,#1 部分可以相当于 __enter__
,#3 部分相当于__exit__
. yield 部分相当于返回的实例。同时当意外发生的时候,发生的位置位于yield 语句部分,所以不会执行#3 部分的代码
例子
with test(value=10)as number:
print('in the with statement:',number)
输出
in the with statement: 1
finish: 11
yield 返回的new_number 作为了number。
更加有用的例子
@contextmanager
def test2(items):
working = items[:]
yield working
items[:]=working[:]
In [113]: test_list = [1,2]
In [114]: with test2(test_list) as working:
...: working.append(3)
...:
In [115]: test_list
Out[115]: [1, 2, 3]
如果意外发生
In [117]: test_list = [1,2]
In [118]: with test2(test_list) as working:
...: working.append(3)
...: raise RuntimeError('something wrong!')
...:
---------------------------------------------------------------------------
RuntimeError Traceback (most recent call last)
<ipython-input-118-bef04ac91803> in <module>()
1 with test2(test_list) as working:
2 working.append(3)
----> 3 raise RuntimeError('something wrong!')
4
RuntimeError: something wrong!
In [119]: test_list
Out[119]: [1, 2]
yield 之后的代码不会被执行
总结 & 废话
contextmanager 使用范围很小,只适用于完全独立的上下文管理器。如果遇上复杂一些的情况,比如要返回的是一些类的实例的话,你还是应该使用class 定义相应的__enter__
, __exit__
。 哈哈哈,真是喜闻乐见。不过研究一下总是有好处的233333,至少with 语句看上去比较酷炫....
参考资料 "Python Cookbook"