也就是說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,則就像什麼都沒發生。
一 with
Python中的with的作用是自動釋放對象,即使對象在使用的過程中有異常拋出。可以使用with的類型必須實現__enter__ __exit__。我的理解是=try...finally{},在finally中調用了釋放函數。
[類似與CSharp中的using(){}關鍵字,用來自動確保調用對象的dispose()方法,即使對象有異常拋出。C#中可以使用using{}的對象必須已經實現了IDispose接口。]
def TestWith():
with open("myfile.txt") as f:
for line in f:
print (line)
f.readline() #f is already clean up here, here will meet ValueError exception
TestWith()
在with語句執行完以後,f對象馬上就被釋放了。所以下面在調用f.readline()會出錯。
二 with + try...except
既能讓對象自動釋放,又包含了異常捕獲的功能。
class controlled_execution(object):
def __init__(self, filename):
self.filename = filename
self.f = None
def __enter__(self):
try:
f = open(self.filename, 'r')
content = f.read()
return content
except IOError as e:
print (e)
def __exit__(self, type, value, traceback):
if self.f:
print ('type:%s, value:%s, traceback:%s' % (str(type), str(value), str(traceback)))
self.f.close()
def TestWithAndException():
with controlled_execution("myfile.txt") as thing:
if thing:
print(thing)
#TestWithAndException()