@Frankchen
2016-03-24T11:38:43.000000Z
字数 1785
阅读 1612
python
with
指令相对于Python里其他的内容来说是很普通的,前提是你理解了它所要解决的问题。考虑一下以下的这些代码:
set things up
try:
do something
finally:
tear things down
在这里,“set things up” 可能是打开一个文件或者取得一些其他的资源,而“tear things down”可能是关闭这个文件或者发布或者移除这个资源。而try-finally
结构保证了“tear things down”部分总是被执行,甚至是在执行这个功能的代码没有结束的情况下也是如此。
若是你经常使用这个功能,把 “set things up”和“tear things down” 写进库函数来复用是很方便的。你可以如下操作:
def controlled_execution(callback):
set things up
try:
callback(thing)
finally:
tear things down
def my_function(thing):
do something
controlled_execution(my_function)
然而这样有点太繁琐,特别是你需要改变局部变量的时候。另一种方法则是使用一次性的产生器,并且使用for-in
指令来“包裹”代码:
def controlled_execution():
set things up
try:
yield thing
finally:
tear things down
for thing in controlled_execution():
do something with thing
但是,在Python2.4版本以前yield
在try-finally
内部是不被允许的。而当这个问题被修复以后(已在2.5版本被修复),而当你知道你只需要执行某些功能一次的时候去使用循环,这仍然是比较怪异的。
所以在考虑了许多替代者之后,GvR和python-dev team之后终于得出了一般化的结论,即使用一个对象(object)而不是产生器来控制一些额外的代码的行为:
class controlled_execution:
def __enter__(self):
set things up
return thing
def __exit__(self, type, value, traceback):
tear things down
with controlled_execution() as thing:
some code
现在,当with
被执行后,Python评估这个表达,在结果值上引用__enter__
方法(被叫做上下文看守),并且分配所有__enter__
返回的值给予as
给的变量。Python将执行代码的本体,在这代码中并且无论发生什么,召唤守卫对象的__exit__
方法。
另外,__exit__
方法能够寻找例外情况,必要时禁止它或者执行它。
若要禁止例外,只需要返回一个真值即可。比如,接下来的__exit__
方法禁止所有的TypeError
,但是允许所有的其他例外通过:
def __exit__(self, type, value, traceback):
# isinstance判断前者是否为后者,返回Ture或者False
return isinstance(value, TypeError)
在Python2.5中,文件对象本身自带有__enter__
和__exit__
方法,前者返回文件对象本身,而后者关闭文件:
>>> f = open("x.txt")
>>> f
<open file 'x.txt', mode 'r' at 0x00AE82F0>
>>> f.__enter__()
<open file 'x.txt', mode 'r' at 0x00AE82F0>
>>> f.read(1)
'X'
>>> f.__exit__(None, None, None)
>>> f.read(1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: I/O operation on closed file
因此,要打开文件,处理其内容,并且需要确保关闭此文件的时候,简单来说你可以这样做:
with open("x.txt") as f:
data = f.read()
do something with data
这不是很难,对吗?