上下文管理器允許你在有需要的時候,精確地分配和釋放資源。
使用上下文管理器最廣泛的案例就是with語句了。
想象下你有兩個需要結對執行的相關操作,然後還要在它們中間放置一段代碼。
上下文管理器就是專門讓你做這種事情的。舉個例子:
with open('some_file', 'w') as opened_file:
opened_file.write('Hola!')
上面這段代碼打開了一個文件,往裡面寫入了一些數據,然後關閉該文件。如果在往文件寫數據時發生異常,它也會嘗試去關閉文件。上面那段代碼與這一段是等價的:
file = open('some_file', 'w')
try:
file.write('Hola!')
finally:
file.close()
當與第一個例子對比時,我們可以看到,通過使用with,許多樣板代碼(boilerplate code)被消掉了。 這就是with語句的主要優勢,它確保我們的文件會被關閉,而不用關注嵌套代碼如何退出。
上下文管理器的一個常見用例,是資源的加鎖和解鎖,以及關閉已打開的文件(就像我已經展示給你看的)。
讓我們看看如何來實現我們自己的上下文管理器。這會讓我們更完全地理解在這些場景背後都發生著什麼。
一個上下文管理器的類,最起碼要定義__enter__和__exit__方法。
讓我們來構造我們自己的開啟文件的上下文管理器,並學習下基礎知識。
class File(object):
def __init__(self, file_name, method):
self.file_obj = open(file_name, method)
def __enter__(self):
return self.file_obj
def __exit__(self, type, value, traceback):
self.file_obj.close()
通過定義__enter__和__exit__方法,我們可以在with語句裡使用它。我們來試試:
with File('demo.txt', 'w') as opened_file:
opened_file.write('Hola!')
我們的__exit__函數接受三個參數。這些參數對於每個上下文管理器類中的__exit__方法都是必須的。我們來談談在底層都發生了什麼。
1. with語句先暫存了File類的__exit__方法
2. 然後它調用File類的__enter__方法
3. __enter__方法打開文件並返回給with語句
4. 打開的文件句柄被傳遞給opened_file參數
5. 我們使用.write()來寫文件
6. with語句調用之前暫存的__exit__方法
7. __exit__方法關閉了文件