Python實用程式與with語句上下文 (contextlib)


Python標準庫中的contextlib模組定義了ContextManager類,其物件可以正確管理程式中的資源。Python具有與上下文管理器一起工作的with關鍵字。檔案物件(由內建的open()函式返回)支援ContextManager API。因此,我們經常在處理檔案時使用with關鍵字。

下面的程式碼塊開啟一個檔案並在其中寫入一些資料。操作完成後,檔案將被關閉,否則檔案描述符可能會洩漏,導致檔案損壞。

f = open("file.txt","w")
f.write("hello world")
f.close()

但是,使用以下語法使用檔案的上下文管理器功能執行相同的檔案操作。

with open("file.txt","w") as f:
f.write("hello world")
print ("file is closed")

如上所述,檔案物件實現了ContextManager。它由with關鍵字啟用。with塊包含要為檔案物件處理的語句。with塊結束後,檔案物件將自動關閉(無需顯式呼叫close()方法)。任何被with塊處理的物件都只在塊內有效,並在其結束時立即被釋放。

ContextManager類有兩個基本方法__enter__()和__exit__()

__enter__() − 當with塊開始時將被呼叫。它表示程式已進入與此物件相關的執行時上下文。

__exit__() − 當with塊結束時被呼叫。它表示程式退出與此物件相關的執行時上下文。

檔案物件也擁有這兩個方法,可以透過以下直譯器會話確認。

>>> f = open("file.txt","w")
>>> f.__enter__()
<_io.TextIOWrapper name = 'file.txt' mode = 'w' encoding = 'cp1252'>
>>> f.write("hello world")
11
>>> f.__exit__()
>>> f.write("hello world")
Traceback (most recent call last):
File "<pyshell#10>", line 1, in <module>
f.write("hello world")
ValueError: I/O operation on closed file.

呼叫__exit__()方法時,檔案將被關閉。這就是為什麼在我們嘗試向已關閉的檔案寫入一些資料後出現ValueError的原因。

下面是contextManager更通用的用法。首先,我們定義一個包含__enter__()和__exit__()方法的類,並使用with語句為其物件啟用contextManager。

import contextlib
class WithExample:
   def __init__(self):
      print ("object initialized")
   def __enter__(self):
      print ("entered context")
   def __exit__(self, *args):
      print ("exited context")
with WithExample() as w:
print ('this is a contextlib example')
print ('used by with statement')
print ('end of with block')

輸出顯示,with塊開始後,__enter__()方法立即執行。塊內的語句將被處理。當塊結束時,__exit__()方法將自動被呼叫。

object initialized
entered context
this is a contextlib example
used by with statement
exited context
end of with block

contextlib模組具有@contextmanager裝飾器,藉助它我們可以編寫一個基於生成器的工廠函式來自動支援with語句。使用裝飾器的檔案物件的上下文管理如下所示:

from contextlib import contextmanager
@contextmanager
def openfile(name):
   try:
      f = open(name, 'w')
      yield f
   finally:
      f.close()
with openfile(file.txt') as f:
f.write('hello world')
print ('file is closed')

因此,ContextManager是Python的一個非常有用的特性,可以有效地管理程式中的資源。

更新於:2020年6月27日

348 次瀏覽

啟動你的職業生涯

透過完成課程獲得認證

開始學習
廣告
© . All rights reserved.