@Frankchen
2016-03-24T11:38:43.000000Z
字数 1785
阅读 1717
python
with指令相对于Python里其他的内容来说是很普通的,前提是你理解了它所要解决的问题。考虑一下以下的这些代码:
set things uptry:do somethingfinally: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 uptry:callback(thing)finally:tear things downdef my_function(thing):do somethingcontrolled_execution(my_function)
然而这样有点太繁琐,特别是你需要改变局部变量的时候。另一种方法则是使用一次性的产生器,并且使用for-in指令来“包裹”代码:
def controlled_execution():set things uptry:yield thingfinally:tear things downfor 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 upreturn thingdef __exit__(self, type, value, traceback):tear things downwith controlled_execution() as thing:some code
现在,当with被执行后,Python评估这个表达,在结果值上引用__enter__方法(被叫做上下文看守),并且分配所有__enter__返回的值给予as给的变量。Python将执行代码的本体,在这代码中并且无论发生什么,召唤守卫对象的__exit__方法。
另外,__exit__方法能够寻找例外情况,必要时禁止它或者执行它。
若要禁止例外,只需要返回一个真值即可。比如,接下来的__exit__方法禁止所有的TypeError,但是允许所有的其他例外通过:
def __exit__(self, type, value, traceback):# isinstance判断前者是否为后者,返回Ture或者Falsereturn 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
这不是很难,对吗?