Python里contextlib工具 上下文管理器工具庫contextlib的妙用

python的contextlib模塊提供了多種簡化上下文管理器創(chuàng)建與使用的工具。1. 使用@contextmanager裝飾器可通過生成器函數(shù)快速定義上下文管理器,yield前部分相當(dāng)于__enter__,后部分相當(dāng)于__exit__。2. closing()可將不支持with的對象包裝成支持形式,如urlopen。3. redirect_stdout()可重定向標(biāo)準(zhǔn)輸出到文件或流,便于測試和日志收集。4. exitstack可用于動態(tài)組合多個上下文,自動管理多個資源的清理。5. suppress()可忽略特定異常,如刪除不存在的文件時避免程序中斷。這些工具使資源管理更簡潔、優(yōu)雅且不易出錯。

python開發(fā)中,處理資源的獲取和釋放是一個常見的需求,比如打開文件、數(shù)據(jù)庫連接、鎖的獲取與釋放等。這時候上下文管理器(context manager)就派上用場了。而 contextlib 模塊就是用來簡化上下文管理器創(chuàng)建和使用的工具庫。

它不僅能幫助我們快速定義自己的上下文管理器,還能將一些原本不支持 with 語句的對象“包裝”成支持的形式。下面我們就來看看它的幾個實用技巧。


使用 @contextmanager 裝飾器快速定義上下文管理器

通常情況下,要自定義一個上下文管理器,需要實現(xiàn) __enter__ 和 __exit__ 方法。但如果你只是想簡單封裝一段代碼邏輯,用類寫起來會有點麻煩。

這時可以用 contextlib.contextmanager 裝飾器配合生成器函數(shù)來實現(xiàn):

立即學(xué)習(xí)Python免費學(xué)習(xí)筆記(深入)”;

from contextlib import contextmanager  @contextmanager def open_file(path, mode):     f = None     try:         f = open(path, mode)         yield f     finally:         if f:             f.close()

這樣你就可以像使用普通文件對象一樣使用它:

with open_file('test.txt', 'w') as f:     f.write('hello')

這個方法的核心在于:yield 上面的部分相當(dāng)于 __enter__,下面的部分相當(dāng)于 __exit__。


把函數(shù)或?qū)ο筠D(zhuǎn)換為上下文管理器:closing() 和 redirect_stdout()

有時候你想把某個對象(比如網(wǎng)絡(luò)連接、套接字、臨時文件等)變成支持 with 的形式,但它們又沒有自帶上下文管理器。這時候可以借助 contextlib.closing():

from contextlib import closing from urllib.request import urlopen  with closing(urlopen('http://example.com')) as page:     print(page.read())

上面這段代碼確保即使 urlopen 返回的對象沒有 __enter__ 和 __exit__ 方法,也能安全關(guān)閉。

另一個常用的是 redirect_stdout(),它可以將標(biāo)準(zhǔn)輸出重定向到文件或其他流中:

from contextlib import redirect_stdout import io  f = io.StringIO() with redirect_stdout(f):     print("This goes to the StringIO object")  print("Captured output:", f.getvalue())

這在測試腳本輸出或者日志收集時非常有用。


組合多個上下文管理器:ExitStack

有時候你需要同時進(jìn)入多個上下文,比如打開多個文件、連接多個資源。雖然你可以嵌套寫多個 with,但如果數(shù)量較多,代碼會顯得冗長。

ExitStack 提供了一種靈活的方式來動態(tài)地組合多個上下文:

from contextlib import ExitStack  with ExitStack() as stack:     files = [stack.enter_context(open(f'test{i}.txt', 'w')) for i in range(3)]     for f in files:         f.write('some content')

每個打開的文件都會自動在 with 塊結(jié)束時被關(guān)閉。這種方式非常適合在運行時動態(tài)決定要打開多少資源的情況。


小技巧:忽略某些異常,避免程序中斷

有些時候你在處理資源時可能會遇到預(yù)期中的異常,比如清理臨時目錄時,目錄可能已經(jīng)不存在了。你可以用 contextlib.suppress() 來忽略特定異常:

from contextlib import suppress import os  with suppress(FileNotFoundError):     os.remove('tempfile.tmp')

這樣即使文件不存在也不會拋出異常。相比用 try…except 包裹,這種寫法更簡潔也更有意圖性。


總的來說,contextlib 提供了一些非常實用的小工具,讓你在處理資源管理時更加優(yōu)雅、簡潔,而且不容易出錯。掌握這些技巧之后,在寫涉及資源控制的代碼時會更加得心應(yīng)手。基本上就這些,用起來不復(fù)雜但確實很實用。

以上就是Python里contextlib

? 版權(quán)聲明
THE END
喜歡就支持一下吧
點贊11 分享