簡單總結
with as 語句的作用主要如下:
1、解決異常退出時資源釋放的問題;
2、解決使用者忘記調用close方法而産生的資源洩漏問題;
也就是說,with as方法最适合容易偷懶或者馬虎的程式員了,從C/C++過來的程式員沒少體驗過資源洩漏以及記憶體問題,而withas語句就可以友善地幫助你從苦海中解脫。
詳細解釋:
看一下官方文檔對with語句的描述:
The with statement:
The with statement is used to wrap the execution of a block with methods defined by a context manager (see section With Statement Context Managers). This allows common try…except…finally usage patterns to be encapsulated for convenient reuse.
with語句是通過一個上下文管理器定義的方法來對一段程式進行打包執行.這将讓常見的try…except…finally模式用法被包裝起來以便重複使用
with_stmt ::= “with” with_item (“,” with_item)* “:” suite
with_item ::= expression [“as” target]
#說白了就是:
with item as target:
The execution of the with statement with one “item” proceeds as follows:
使用with語句來執行一個item過程如下:
1、The context expression (the expression given in the with_item) is evaluated to obtain a context manager.
檢測到上下文表達式,進而擷取上下文管理器
2、The context manager’s exit() is loaded for later use.
上下文管理器的exit()方法會被載入以便之後使用
3、The context manager’s enter() method is invoked.
上下文管理器的 enter() 方法被激活(執行)
4、If a target was included in the with statement, the return value from enter() is assigned to it.
如果在with語句中目标被包含,那麼來自enter()的傳回值就會背附帶過來。
Note The with statement guarantees that if the enter() method returns without an error, then exit() will always be called. Thus, if an error occurs during the assignment to the target list, it will be treated the same as an error occurring within the suite would be. See step 6 below.
注意,with語句遵循:如果enter ()方法傳回沒有錯誤,則exit ()将始終被調用。 是以,如果在配置設定給目标清單期間發生錯誤,則将被視為與套件内發生的錯誤相同。 請參閱下面的步驟6。
5、The suite is executed.
這段程式被執行
6、The context manager’s exit() method is invoked. If an exception caused the suite to be exited, its type, value, and traceback are passed as arguments to exit(). Otherwise, three None arguments are supplied.
上下文管理器的exit() 方法被執行,如果這組程式被一個意外造成終止,那麼這個組程式的類型、傳回值、還有跟蹤回報被當做檔案傳遞到exit()中。如果三個參數沒有被提供,這個過程将造成不一樣的結果。
If the suite was exited due to an exception, and the return value from the exit() method was false, the exception is reraised. If the return value was true, the exception is suppressed, and execution continues with the statement following the with statement.
如果這段程式因為意外被迫終止,由exit() 方法得到的傳回值為假,那麼意外将會被重新提出。如果傳回值是真,意外将被隐匿,程式将繼續往下執行。
If the suite was exited for any reason other than an exception, the return value from exit() is ignored, and execution proceeds at the normal location for the kind of exit that was taken.
如果這段程式不是因為意外所終止,來自 exit()的傳回值将被忽略,程式會在正常位置處理執行所采用的退出類型。
而上面所說的内容管理器主要是用來管理在with申明中定義的運作時内容(runtime context),也可以說是一種環境,一個狀态。 該管理器實作了兩個方法,一個是enter()方法,一個是exit()方法。
enter()方法主要是進入運作時内容(runtime context)并傳回與之相對應的對象。 該方法的傳回值的會綁定到使用該context Manager的with 語句中as辨別符之後的内容。舉個例子:
with open('text.txt') as file
file.read()
該内容管理器(context manager)中的enter()方法傳回的是一個檔案對象,該對象指派給了file。
exit(exc_type, exc_val, exc_tb)方法就是在結束這個運作時内容或環境(runtime context)并傳回一個布爾值的變量來确定是否忽略中途出現的異常情況。如果中途在with語句中的執行體中出現了什麼問題。就會把對應的異常類型,值以及回溯資訊傳給該方法,沒有異常就傳入None。如果有異常傳入并且布爾值為真就忽略該異常,如果有異常傳入但布爾值為假就像正常一樣抛出異常。内容管理器的有點就是将try…except…finally的複用性提高。
執行一段程式測試一下輸出結果
編譯環境:Python3.6.2,Pycharm
class Test:
def __enter__(self):
print("this is in __enter__")
return "enter_test"
def __exit__(self, exc_type, exc_val, exc_tb):
print("this is in __exit__")
def test_funcion():
return Test()
if __name__ == "__main__":
with test_funcion() as test:
print("The Test return value is", test)
執行結果
this is in __enter__
The Test return value is enter_test
this is in __exit__