Python中的with語句與上下文管理器學習總結
0、關于上下文管理器
上下文管理器是可以在with語句中使用,擁有__enter__和__exit__方法的對象。
with manager as var: do_something(var)
相當于以下情況的簡化:
var = manager.__enter__() try: do_something(var) finally: manager.__exit__()
換言之,PEP 343中定義的上下文管理器協(xié)議允許將無聊的try...except...finally結構抽象到一個單獨的類中,僅僅留下關注的do_something部分。
__enter__方法首先被調(diào)用。它可以返回賦給var的值。as部分是可選的:如果它不出現(xiàn),enter的返回值簡單地被忽略。
with語句下的代碼被執(zhí)行。就像try子句,它們或者成功執(zhí)行到底,或者break,continue或return,或者可以拋出異常。無論哪種情況,該塊結束后,__exit__方法被調(diào)用。如果拋出異常,異常信息被傳遞給__exit__,這將在下一章節(jié)討論。通常情況下,異??杀缓雎?,就像在finally子句中一樣,并且將在__exit__結束后重新拋出。
比如說我們想確認一個文件在完成寫操作之后被立即關閉:
>>> class closing(object):
... def __init__(self, obj):
... self.obj = obj
... def __enter__(self):
... return self.obj
... def __exit__(self, *args):
... self.obj.close()
>>> with closing(open('/tmp/file', 'w')) as f:
... f.write('the contents\n')
這里我們確保了當with塊退出時調(diào)用了f.close()。因為關閉文件是非常常見的操作,該支持已經(jīng)出現(xiàn)在file類之中。它有一個__exit__方法調(diào)用close,并且本身可作為上下文管理器。
>>> with open('/tmp/file', 'a') as f:
... f.write('more contents\n')
try...finally常見的用法是釋放資源。各種不同的情況實現(xiàn)相似:在__enter__階段資源被獲得,在__exit__階段釋放,如果拋出異常也被傳遞。正如文件操作,往往這是對象使用后的自然操作,內(nèi)置支持使之很方便。每一個版本,Python都在更多的地方提供支持。
1、如何使用上下文管理器:
如何打開一個文件,并寫入"hello world"
filename="my.txt"
mode="w"
writer=open(filename,mode)
writer.write("hello world")
writer.close()
當發(fā)生異常時(如磁盤寫滿),就沒有機會執(zhí)行第5行。當然,我們可以采用try-finally語句塊進行包裝:
writer=open(filename,mode)
try:
writer.write("hello world")
finally:
writer.close()
當我們進行復雜的操作時,try-finally語句就會變得丑陋,采用with語句重寫:
with open(filename,mode) as writer:
writer.write("hello world")
as指代了從open()函數(shù)返回的內(nèi)容,并把它賦給了新值。with完成了try-finally的任務。
2、自定義上下文管理器
with語句的作用類似于try-finally,提供一種上下文機制。要應用with語句的類,其內(nèi)部必須提供兩個內(nèi)置函數(shù)__enter__和__exit__。前者在主體代碼執(zhí)行前執(zhí)行,后者在主體代碼執(zhí)行后執(zhí)行。as后面的變量,是在__enter__函數(shù)中返回的。
class echo():
def output(self):
print "hello world"
def __enter__(self):
print "enter"
return self #可以返回任何希望返回的東西
def __exit__(self,exception_type,value,trackback):
print "exit"
if exception_type==ValueError:
return True
else:
return Flase
>>>with echo as e:
e.output()
輸出:
enter hello world exit
def __exit__(self,exc_type,exc_value,exc_tb)
其中,exc_type:異常類型;exc_value:異常值;exc_tb:異常追蹤信息
當__exit__返回True時,異常不傳播
3、contextlib模塊
contextlib模塊的作用是提供更易用的上下文管理器,它是通過Generator實現(xiàn)的。contextlib中的contextmanager作為裝飾器來提供一種針對函數(shù)級別的上下文管理機制,常用框架如下:
from contextlib import contextmanager
@contextmanager
def make_context():
print 'enter'
try:
yield "ok"
except RuntimeError,err:
print 'error',err
finally:
print 'exit'
>>>with make_context() as value:
print value
輸出為:
enter ok exit
其中,yield寫入try-finally中是為了保證異常安全(能處理異常)as后的變量的值是由yield返回。yield前面的語句可看作代碼塊執(zhí)行前操作,yield之后的操作可以看作在__exit__函數(shù)中的操作。
以線程鎖為例:
@contextlib.contextmanager def loudLock(): print 'Locking' lock.acquire() yield print 'Releasing' lock.release() with loudLock(): print 'Lock is locked: %s' % lock.locked() print 'Doing something that needs locking' #Output: #Locking #Lock is locked: True #Doing something that needs locking #Releasing
4、contextlib.nested:減少嵌套
對于:
with open(filename,mode) as reader:
with open(filename1,mode1) as writer:
writer.write(reader.read())
可以通過contextlib.nested進行簡化:
with contextlib.nested(open(filename,mode),open(filename1,mode1)) as (reader,writer): writer.write(reader.read())
在python 2.7及以后,被一種新的語法取代:
with open(filename,mode) as reader,open(filename1,mode1) as writer: writer.write(reader.read())
5、contextlib.closing()
file類直接支持上下文管理器API,但有些表示打開句柄的對象并不支持,如urllib.urlopen()返回的對象。還有些遺留類,使用close()方法而不支持上下文管理器API。為了確保關閉句柄,需要使用closing()為它創(chuàng)建一個上下文管理器(調(diào)用類的close方法)。
import contextlib
class myclass():
def __init__(self):
print '__init__'
def close(self):
print 'close()'
with contextlib.closing(myclass()):
print 'ok'
輸出:
__init__ ok close()
相關文章
Python+SQLAlchemy輕松實現(xiàn)管理數(shù)據(jù)庫
QLAlchemy是一個強大的ORM(對象關系映射)庫,它允許您通過Python代碼與關系型數(shù)據(jù)庫進行交互,本文我們將學習如何使用Python和SQLAlchemy庫來輕松管理數(shù)據(jù)庫,需要的可以參考下2023-05-05
Django框架HttpResponse和HttpRequest對象學習
這篇文章主要介紹了Django框架HttpResponse和HttpRequest對象學習,有需要的朋友可以借鑒參考下,希望可以有所幫助,祝大家早日升職加薪2021-09-09
Python通過PIL獲取圖片主要顏色并和顏色庫進行對比的方法
這篇文章主要介紹了Python通過PIL獲取圖片主要顏色并和顏色庫進行對比的方法,實例分析了Python通過PIL模塊操作圖片的技巧,具有一定參考借鑒價值,需要的朋友可以參考下2015-03-03

