傳智播客 with與「上下文管理器」 學習筆記

2021-10-02 09:41:37 字數 3067 閱讀 9853

目錄

什麼是上下文(context)

上下文管理器

實現上下文管理器的另外方式 總結

對於系統資源如檔案、資料庫連線、socket 而言,應用程式開啟這些資源並執行完業務邏輯之後,必須做的一件事就是要關閉(斷開)該資源。

比如 python 程式開啟乙個檔案,往檔案中寫內容,寫完之後,就要關閉該檔案,否則會出現什麼情況呢?極端情況下會出現 "too many open files" 的錯誤,因為系統允許你開啟的最大檔案數量是有限的。

同樣,對於資料庫,如果連線數過多而沒有及時關閉的話,就可能會出現 "can not connect to mysql server too many connections",因為資料庫連線是一種非常昂貴的資源,不可能無限制的被建立。

來看看如何正確關閉乙個檔案。

普通版:

def m1():

f = open("output.txt", "w")

f.write("python之禪")

f.close()

這樣寫有乙個潛在的問題,如果在呼叫 write 的過程中,出現了異常進而導致後續**無法繼續執行,close 方法無法被正常呼叫,因此資源就會一直被該程式占用者釋放。那麼該如何改進**呢?

高階版:

def m2():

f = open("output.txt", "w")

try:

f.write("python之禪")

except ioerror:

print("oops error")

finally:

f.close()

改良版本的程式是對可能發生異常的**處進行 try 捕獲,使用 try/finally 語句,該語句表示如果在 try **塊中程式出現了異常,後續**就不再執行,而直接跳轉到 except **塊。而無論如何,finally 塊的**最終都會被執行。因此,只要把 close 放在 finally **中,檔案就一定會關閉。

高階版:

def m3():

with open("output.txt", "r") as f:

f.write("python之禪")

一種更加簡潔、優雅的方式就是用 with 關鍵字。open 方法的返回值賦值給變數 f,當離開 with **塊的時候,系統會自動呼叫 f.close() 方法, with 的作用和使用 try/finally 語句是一樣的。那麼它的實現原理是什麼?在講 with 的原理前要涉及到另外乙個概念,就是上下文管理器(context manager)。

上下文在不同的地方表示不同的含義,要感性理解。context其實說白了,和文章的上下文是乙個意思,在通俗一點,我覺得叫環境更好。....

林沖大叫一聲「啊也!」....

問:這句話林沖的「啊也」表達了林沖怎樣的心裡?

答:啊你**頭啊!

看,一篇文章,給你摘錄一段,沒前沒後,你讀不懂,因為有語境,就是語言環境存在,一段話說了什麼,要通過上下文(文章的上下文)來推斷。

看這些都是上下文的典型例子,理解成環境就可以,(而且上下文雖然叫上下文,但是程式裡面一般都只有上文而已,只是叫的好聽叫上下文。。程序中斷在作業系統中是有上有下的,不過不這個高深的問題就不要深究了。。。)

任何實現了 __enter__() 和 __exit__() 方法的物件都可稱之為上下文管理器,上下文管理器物件可以使用 with 關鍵字。顯然,檔案(file)物件也實現了上下文管理器。

那麼檔案物件是如何實現這兩個方法的呢?我們可以模擬實現乙個自己的檔案類,讓該類實現 __enter__() 和 __exit__() 方法。

class file():

def __init__(self, filename, mode):

self.filename = filename

self.mode = mode

def __enter__(self):

print("entering")

self.f = open(self.filename, self.mode)

return self.f

def __exit__(self, *args):

print("will exit")

self.f.close()

__enter__() 方法返回資源物件,這裡就是你將要開啟的那個檔案物件,__exit__() 方法處理一些清除工作。

因為 file 類實現了上下文管理器,現在就可以使用 with 語句了。

with file('out.txt', 'w') as f:

print("writing")

f.write('hello, python')

這樣,你就無需顯示地呼叫 close 方法了,由系統自動去呼叫,哪怕中間遇到異常 close 方法也會被呼叫。

python 還提供了乙個 contextmanager 的裝飾器,更進一步簡化了上下文管理器的實現方式。通過 yield 將函式分割成兩部分,yield 之前的語句在 __enter__ 方法中執行,yield 之後的語句在 __exit__ 方法中執行。緊跟在 yield 後面的值是函式的返回值。

from contextlib import contextmanager

@contextmanager

def my_open(path, mode):

f = open(path, mode)

yield f

f.close()

呼叫

with my_open('out.txt', 'w') as f:

f.write("hello , the ******st context manager")

python 提供了 with 語法用於簡化資源操作的後續清除操作,是 try/finally 的替代方法,實現原理建立在上下文管理器之上。此外,python 還提供了乙個 contextmanager 裝飾器,更進一步簡化上下管理器的實現方式。

with與上下文管理器

def m1 f open source.txt w f.close 如果在呼叫 write 的過程中,出現了異常進而導致後續 無法繼續執行,close 方法無法被正常呼叫,因此資源就會一直被該程式占用,無法及時釋放占用的檔案資源。f open source.txt w try except exc...

with上下文管理器

在執行 with 語句時,首先執行 with 後面的 open 執行完 後,會將 的結果通過 as 儲存到 f 中 然後在下面實現真正要執行的操作 在操作後面,並不需要寫檔案的關閉操作,檔案會在使用完後自動關閉 實際上,在檔案操作時,並不是不需要寫檔案的關閉,而是檔案的關閉操作在 with 的上下文...

with上下文管理器

上下文管理器 任何實現了enter 和exit 法的物件都可稱之為上下 管理 器,上下 管理器物件可以使 with 關鍵字。顯然,件 file 物件也實現 了上下 管理器 方法一class file def init self,filename,mode self.filename filename...