Context Manager
文檔翻譯
Python with
語句支持上下文管理器定義的運行時上下文概念(runtime context). 用戶定義的類實現(xiàn)一對方法來實現(xiàn)此上下文協(xié)議, 在語句體執(zhí)行前進入上下文, 在與語句體結(jié)束后退出上下文
-
contextmanager.__enter__()
此方法用來實現(xiàn)進入運行時上下文,并返回此上下文關(guān)聯(lián)的對象或自身對象. 此方法返回的值綁定到
as
語句后的標(biāo)識符上.一個返回自身的上下文例子是:
file object
.file object
返回自身在調(diào)用__enter__()
方法后.with open("xxx.txt") as f: f.read()
一個返回關(guān)聯(lián)對象的例子是:
decimal.localcontext()
.具體用法省略. -
contextmanager.__exit__(exc_type, exc_val, exc_tb)
此方法用來實現(xiàn)退出運行時上下文, 并返回一個布爾值--用來指示如果有應(yīng)該抑制的異常發(fā)生. 如果執(zhí)行
with
語句塊時發(fā)生了一個異常, 此方法的參數(shù)包含異常的類型/值/堆棧信息. 否則, 所有三個參數(shù)為None
.此方法返回
True
時將導(dǎo)致with
語句抑制異常的拋出然后繼續(xù)with
語句后的語句.這個語句執(zhí)行完成后異常將繼續(xù)向上拋出.此方法執(zhí)行期間產(chǎn)生的異常將覆蓋其他任何with
語句體中的異常.傳入此方法的異常不應(yīng)該顯式的重新拋出,而是, 這個方法應(yīng)該返回一個
False
來表明此方法成功執(zhí)行完成并且不會異常拋出的異常. 這用來允許上下文管理器代碼容易的來檢測是否此方法確實失敗.
Python定義了幾個上下文管理器來支持線程同步/文件立即關(guān)閉等. 除了上下文管理器協(xié)議之外, 對特定類型沒有特殊的處理.
Python的生成器對象和contextlib.contextmanager
裝飾器提供了一個簡便的方式來實現(xiàn)上下文管理器協(xié)議.如果一個generator function
被contextlib.contextmanager
裝飾器裝飾, 將返回一個實現(xiàn)了__enter__()
和__exit__()
方法的上下文管理器, 而不是未被裝飾的生成器函數(shù)返回的迭代器.
詳解
上下文管理器對象存在的目的是管理with
語句, 就像迭代器存在是為了管理for
語句.
with
語句的目的: 簡化try/finally
模式.
try/finally
模式: 用于保證一段代碼運行完畢后執(zhí)行某項操作, 即便那段代碼由于異常/return語句或sys.exit()
調(diào)用而終止, 也會執(zhí)行指定的操作.
finally
子句中的代碼通常用于釋放重要的資源, 或者還原臨時變更的狀態(tài).
上下文管理器協(xié)議包含__enter__
和__exit__
方法.
with
語句開始運行時, 會在上下文管理器對象上調(diào)用__enter__
方法.
解釋器調(diào)用
__enter__
方法時, 除了隱式的self
之外,不會傳入任何參數(shù).
with
語句運行結(jié)束后, 會在上下文管理器對象上調(diào)用__exit__
方法, 以此扮演finally
子句的角色.
傳給
__exit__
方法的三個參數(shù)解釋如下:
exc_type
: 異常類(例如ZeroDivisionError
)exc_value
: 異常實例. 有時會有參數(shù)傳給異常構(gòu)造方法, 例如錯誤消息. 這些參數(shù)可以使用exc_value.args
獲取.traceback
:traceback
對象
不管控制流程以哪種方式退出with
塊, 都會在上下文管理器對象上調(diào)用__exit__
方法, 而不是在__enter__
方法返回的對象上調(diào)用.
with
語句的as
子句是可選的. 比如, 打開文件的open
函數(shù),必須加上as
子句, 以便獲得文件的引用.
有些上下文管理器會返回None
, 因為沒什么有用的對象能提供給用戶.
Python標(biāo)準庫示例
- 在
sqlite3
模塊中用于管理事務(wù) - 在
threading
模塊中用于維護鎖/條件/信號量. - 為
Decimal
對象的算術(shù)運算設(shè)置環(huán)境, 參考decimal.localcontext
- 為了測試臨時給對象打補丁, 參見
unittest.mock.patch
函數(shù)文檔.