Python的上下文管理器

2021-08-20 05:56:53 字數 3624 閱讀 9403

經常在python**中看到with語句,仔細分析下,會發現這個with語句功能好強,可以自動關閉資源。這個在python中叫上下文管理器context manager。那我們要怎麼用它,什麼時候用它呢。這裡我們就來聊一聊。

很多情況,當我們使用完乙個資源後,我們需要手動的關閉掉它,比如操作檔案,建立資料庫連線等。但是,在使用資源的過程中,如果遇到異常,很可能錯誤被直接丟擲,導致來不及關閉資源。所以在大部分程式語言裡,我們使用」try-finally」語句來確保資源會關閉。比如下面的python寫檔案**:

try:

f = open('test.txt', 'a+')

f.write('foo\n')

finally:

f.close()

這樣做固然沒有問題,但是當」try-finally」中間的邏輯複雜,而且還帶有各種巢狀的話,**就很不容易維護。python的with語句,可以說功能同上面的」try-finally」幾乎一樣,但**看上去簡潔的多,我們來實現同樣的功能:

with

open('test.txt', 'a+') as f:

f.write('foo\n')

with語句後面跟著open()方法,如果它有返回值的話,可以使用as語句將其賦值給f。在with語句塊退出時,」f.close()」方法會自動被呼叫,即使」f.write()」出現異常,也能確保close()方法被呼叫。

上例中」open()」方法是python自帶的,那我們怎麼定義自己的型別來使用with語句呢。其實只要你的類定義了」enter()」和」exit()」方法,就可以使用python的上下文管理器了。」enter()」方法會在with語句進入時被呼叫,其返回值會賦給as關鍵字後的變數;而」exit()」方法會在with語句塊退出後自動被呼叫。

我們來實現個跟上節一樣的檔案寫入功能:

class

openfiledemo

(object):

def__init__

(self, filename):

self.filename = filename

def__enter__

(self):

self.f = open(self.filename, 'a+')

return self.f

def__exit__

(self, exc_type, exc_val, exc_tb):

self.f.close()

with openfiledemo('test.txt') as f:

f.write('foo\n')

肯定有朋友注意到上面的」exit()」帶了三個引數,是的,他們是用來異常處理的。大部分情況下,我們希望with語句中遇到的異常最後被丟擲,但也有時候,我們想處理這些異常。」exit()」方法中的三個引數exc_type, exc_val, exc_tb分別代表異常型別,異常值,和異常的traceback。當你處理完異常後,你可以讓」exit()」方法返回true,此時該異常就會不會再被丟擲。比如我們將上例中的」exit()」方法改一下:

def

__exit__

(self, exc_type, exc_val, exc_tb):

self.f.close()

if exc_type != syntaxerror:

return

true

return

false

# only raise exception when syntaxerror

現在,如果遇到syntaxerror的話,異常會被正常丟擲,而其他異常的話都會被忽略。

python中還有乙個contextlib模組提供一些簡便的上下文管理器功能。

closing()方法

如果說with語句塊在退出時會自動呼叫」exit()」方法的話,那用了」contextlib.closing()」的with語句塊則在退出時會自動呼叫」close()」方法。看一下示例:

import contextlib

class

resource

(object):

defopen

(self):

print

'open resource'

defclose

(self):

print

'close resource'

with contextlib.closing(resource()) as r:

r.open()

程式執行後,會列印出

open resource

close resource

說明resource類建立的物件被賦給了as關鍵字後面的變數r,而with語句塊退出時,自動呼叫了」r.close()」方法。

「@contextlib.contextmanager」是乙個裝飾器,由它修飾的方法會有兩部分構成,中間由yield關鍵字分開。由此方法建立的上下文管理器,在**塊執行前會先執行yield上面的語句;在**塊執行後會再執行yield下面的語句。看個例子比較容易明白:

import contextlib

import time

@contextlib.contextmanager

deftimeit

(): start = time.time()

yield

end = time.time()

usedtime = (end - start) * 1000

print

'use time %d ms' % usedtime

with timeit():

time.sleep(1)

這個」timeit()」方法實現了乙個計時器,它會計算由他生成的with語句塊執行時間。可以看出,yield上面的語句就如同之間介紹過的」enter()」方法,而yield下面的語句就如同」exit()」方法。而yield部分就是with語句塊中的**。如果yield後面帶引數的話,我們就可以用as關鍵字賦值給後面的變數,比如上例:

@contextlib.contextmanager

deftimeit

(): start = time.time()

yield start

#...

with timeit() as starttime:

print starttime

#...

需要注意的是,」@contextlib.contextmanager」不像之前介紹的」exit()」方法,遇到異常也會執行。也就是with語句塊丟擲異常的話,yield後面的**將不會被執行。所以,必要時你需要對yield語句使用」try-finally」。

**:

python 上下文管理器

上下文管理器允許你在有需要的時候,精確地分配和釋放資源。使用上下文管理器最廣泛的案例就是with語句了。想象下你有兩個需要結對執行的相關操作,然後還要在它們中間放置一段 上下文管理器就是專門讓你做這種事情的。舉個例子 with open some file w as opened file open...

python上下文管理器

上下文管理器是乙個包裝任意 塊的物件。上下文管理器保證進入上下文管理器時,每次 執行的一致性 當退出上下文管理器時,相關資源會被正確 這裡被正確 指的是在 exit 方法自定義 比如關閉資料庫游標 值得注意的是,上下文管理器一定能夠保證退出步驟的執行。如果進入上下文管理器,根據定義,一定會有退出步驟...

Python 上下文管理器

python中的上下文管理器是乙個包裝任意 塊的物件。它在處理資源的開啟關閉 異常的處理等方面有很好的實現方法。1.上下文管理器的語法 假設我們需要讀取乙個檔案中的資料,如下 try test file open test.txt r contents test file.read finally ...