|
1
2
3
4
5
6
|
alist=[]with ListTrans(alist) as working: working.append(1) working.append(2) raise RuntimeError(‘we are hosed‘)print alist |
生成:
|
1
|
RuntimeError: we are hosed |
alist无变化。
可以捕捉异常:
|
1
2
3
4
5
6
7
8
9
|
alist=[]try: with ListTrans(alist) as working: working.append(1) working.append(2) raise RuntimeError(‘we are hosed‘)except RuntimeError as e: print eprint alist |
生成:
|
1
2
|
we are hosed[] |
当然,也可以简单的将__exit__的返回值设为True来忽略异常。
4.contextmanager装饰器
@contextmanager
contextlib模块的contextmanager装饰器可以更方便的实现上下文管理器。
任何能够被yield关键词分割成两部分的函数,都能够通过装饰器装饰的上下文管理器来实现。任何在yield之前的内容都可以看做在代码块执行前的操作,
而任何yield之后的操作都可以放在exit函数中。
|
1
2
3
4
5
6
7
8
9
10
11
|
from contextlib import contextmanager@contextmanagerdef listTrans(alist): thecopy=list(alist) yield thecopy alist[:]=thecopyalist=[]with listTrans(alist) as working: working.append(1) working.append(2)print alist |
yield返回的值相当于__enter__的返回值。
要注意的是,这不是异常安全的写法,也就是说,当出现异常时,yield后的语句是不会执行的,想要异常安全,可用try捕捉异常:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
from contextlib import contextmanager@contextmanagerdef listTrans(alist): thecopy=list(alist) try: yield thecopy except RuntimeError: pass alist[:]=thecopyalist=[]with listTrans(alist) as working: working.append(1) working.append(2) raise RuntimeError |
nested与closing
contextlib模块还有两个好玩的方法:nested,closing。
nested:用来更方便的减少嵌套写法:
当要嵌套的写上下文管理器时:
|
1
2
3
|
with open(‘toReadFile‘, ‘r‘) as reader: with open(‘toWriteFile‘, ‘w‘) as writer: writer.writer(reader.read()) |
可以用nested简化写法:
|
1
2
3
|
with contextlib.nested(open(‘fileToRead.txt‘, ‘r‘), open(‘fileToWrite.txt‘, ‘w‘)) as (reader, writer): writer.write(reader.read()) |
python2.7后nested就过时了:
|
1
2
|
with open(‘fileToRead.txt‘, ‘r‘) as reader,open(‘fileToWrite.txt‘, ‘w‘) as writer: writer.write(reader.read()) |
closing(object):创建上下文管理器,在执行过程离开with语句时自动执行object.close():
|
1
2
3
4
5
6
7
|
class Door(object) : def open(self) : print ‘Door is opened‘ def close(self) : print ‘Door is closed‘with contextlib.closing(Door()) as door : door.open() |