with從Python 2.5就有,需要from __future__ import with_statement。
自python 2.6開始,成為默認關鍵字。
在What's new in python2.6/3.0中,明確提到:
The ‘
with
‘ statement is a control-flow structure whose basic
structure is:
with expression [as variable]:
with-block
也就是說with是一個控制流語句,跟if/for/while/try之類的是一類的,with可以用來簡化try finally代碼,看起來可以比try finally更清晰。
這里新引入了一個"上下文管理協議"context management protocol,實現方法是為一個類定義__enter__和__exit__兩個函數。
with expresion as variable的執行過程是,首先執行__enter__函數,它的返回值會賦給as后面的variable,想讓它返回什么就返回什么,只要你知道怎么處理就可以了,如果不寫as variable,返回值會被忽略。
然后,開始執行with-block中的語句,不論成功失敗(比如發生異常、錯誤,設置sys.exit()),在with-block執行完成后,會執行__exit__函數。
這樣的過程其實等價於:
try:
執行 __enter__的內容
執行 with_block.
finally:
執行 __exit__內容
只不過,現在把一部分代碼封裝成了__enter__函數,清理代碼封裝成__exit__函數。
我們可以自己實現一個例子:
import sys
class test:
def __enter__(self):
print("enter")
return 1
def __exit__(self,*args):
print("exit")
return True
with test() as t:
print("t is not the result of test(), it is __enter__ returned")
print("t is 1, yes, it is {0}".format(t))
raise NameError("Hi there")
sys.exit()
print("Never here")
注意:
1,t不是test()的值,test()返回的是"context manager object",是給with用的。t獲得的是__enter__函數的返回值,這是with拿到test()的對象執行之后的結果。t的值是1.
2,__exit__函數的返回值用來指示with-block部分發生的異常是否要re-raise,如果返回False,則會re-raise with-block的異常,如果返回True,則就像什么都沒發生。
