Python 進階: 上下文管理器
在Python中,上下文管理器(Context Manager)是一種用于管理資源(如文件、網絡連接、鎖等)的對象,它確保在使用完資源后能夠正確釋放或清理資源。
上下文管理器通常與with語句一起使用。一個著名的例子是 with open() 語句:
with open('notes.txt', 'w') as f:
f.write('some todo...')
這將打開一個文件,并確保在程序執行離開 with 語句的上下文之后自動將其關閉。
它還處理異常,并確保即使在發生異常的情況下也能正確關閉文件。 在內部,上面的代碼翻譯成這樣的東西:
f = open('notes.txt', 'w')
try:
f.write('some todo...')
finally:
f.close()
應用場景
- 成對操作:打開/關閉、獲取/釋放、開始/結束
- 資源清理:需要確保資源釋放(即使發生異常)
- 狀態切換:需要臨時修改全局狀態后恢復
- 異常處理:需要統一處理特定錯誤
- 性能監控:需要精確測量代碼塊執行時間
自定義上下文管理器
- __enter__():進入上下文時調用,返回資源對象
- __exit__():退出上下文時調用,處理異常和清理
class ManagedFile:
def __init__(self, filename):
print('init', filename)
self.filename = filename
def __enter__(self):
print('enter')
self.file = open(self.filename, 'w')
return self.file
def __exit__(self, exc_type, exc_value, exc_traceback):
if self.file:
self.file.close()
print('exit')
with ManagedFile('notes.txt') as f:
print('doing stuff...')
f.write('some todo...')
contextlib 裝飾器
除了編寫類,我們還可以編寫一個生成器函數,并使用 contextlib.contextmanager 裝飾器對其進行裝飾。 然后,我們也可以使用 with 語句調用該函數。
對于這種方法,函數必須在 try 語句中 yield 資源,并且釋放資源的 __exit__ 方法的所有內容現在都在相應的 finally 語句內。
from contextlib import contextmanager
@contextmanager
def file_manager(filename, mode):
file = open(filename, mode) # 相當于 __enter__
try:
yield file # 返回資源對象
finally:
file.close() # 相當于 __exit__
# 使用示例
with file_manager("test.txt", "w") as f:
f.write("Hello Context Manager!")
高級功能
(1) 異常處理
在 __exit__() 中可通過參數獲取異常信息:
- exc_type:異常類型
- exc_val:異常值
- exc_tb:異常堆棧
def __exit__(self, exc_type, exc_val, exc_tb):
if exc_type:
print(f"Exception handled: {exc_val}")
self.cleanup()
return True # 返回 True 表示異常已被處理
(2) 嵌套上下文管理器
with open("file1.txt") as f1, open("file2.txt") as f2:
data1 = f1.read()
data2 = f2.read()
# 自動關閉兩個文件
(3) 異步上下文管理器
class AsyncConnection:
async def __aenter__(self):
await self.connect()
return self
async def __aexit__(self, exc_type, exc, tb):
await self.close()
# 使用
async with AsyncConnection() as conn:
await conn.send_data()
上下文管理器通過封裝資源管理邏輯,顯著提升代碼的可讀性和健壯性。掌握其自定義方法和高級特性,能讓你編寫更優雅、安全的 Python 代碼。