在Python中with关键字很常用,相信你也经常遇见,例如:
if isinstance(self.commands, str): with(settings(warn_only = True)): sudo(self.commands, shell=False)你或许会困惑with到底是个什么东西?其实with关键字并不难理解今天我们就来说说with statement
考虑下面这段代码:
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)
这种方法将上面的"do something" 提取出来作为一个函数 然后传给我们封装好了的controlled_execution并执行,这种方法看着有点别扭感觉,代码不是很清晰.
另外一种方式是使用“yield”
def controlled_execution(): set things up try: yield thing finally: tear things down for thing in controlled_execution(): do something with thing
但是在 Python 2.4之前 yield是不允许在 try-finally中使用的,同样别扭的是用了一个loop 结构但是你知道你只执行这个代码一次。
所以考虑到前面两种解决方案的缺点,GvR 和 Python-dev 团队最后想出了一个通用的方法那就是with statement
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__ 方法并且把返回的值赋值给as 后面的变量。Python会执行with下面的“some code”并且不管“some code”中发生了什么都会调用 __exit__ 方法。
另外__exit__方法还可以处理异常如返回一个正确的值,例如
def __exit__(self, type, value, traceback): return isinstance(value, TypeError)
In Python 2.5, the file object has been equipped with __enter__ and__exit__ methods; the former simply returns the file object itself, and the latter closes the file:
在Python 2.5中,文件对象也可以和__enter__ and__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
<span class="pykeyword" style="color:rgb(178,34,34);"></span>
with open("x.txt") as f: data = f.read() do something with data