上下文管理器是在Python 2.5加入的功能,什么是上下文管理器,Python’swithstatement supports the concept of a runtime contextdefined by a context manager.This is implemented using two separate methods
that allow user-defined classes to define a runtime context that is entered
before the statement body is executed and exited when the statement ends.這是文檔中對它的解釋。
所以,他的任務就是,在代碼塊執行前,做準備工作,在代碼塊執行完成后,做結束處理工作,也就是白話中的收尾。
他的優點不僅使代碼的可讀性更強并且減少了錯誤的幾率。
我們自己也可以實現一個上下文管理器:
當然要實現一個上下文管理器,必須實現兩個方法,一個__enter__方法,一個__exit__方法。
前者在進入代碼塊之前調用,后者在代碼塊執行完成后調用。
class ContextManagerDemo:
? ? ? ? ?def __enter__(self):
? ? ? ? ? ? ? ?print 'Entering the block'
? ? ? ? ?def __exit__(self,type,value,traceback):
? ? ? ? ? ? ? ? print 'Exiting the block'
with ?ContextManagerDemo():
? ? ? ? ?print 'In the block'
#Output:
? ? ? ? ? ? ? Entering the block
? ? ? ? ? ? ? In the block
? ? ? ? ? ? ?Exiting the block
這是一個非常簡單的例子,那么異常處理放在哪里呢。
如果語句塊發生了異常,__exit__方法就會被調用,而異常將會被重新raise。如果我們不想讓異常被重新raise.也是有辦法的,我們讓__exit__方法返回True就可以阻止(不推薦)。
完備的__exit__方法名為:def __exit__(self,exc_type,exc_val,exc_tb) ? # (異常類型,異常值,異常追蹤信息)
我們還可以使用裝飾器和生成器來實現上下文管理器。python 有個contextlib模塊可以提供更易用的上下文管理器。
1.contextmanager
from contextlib import contextmanager
@contextmanager
def tag(name):
? ? ? ?print "<%s>" % name
? ? ? ?yield
? ? ? ?print "</%s>" % name
>>> with tag("h1"):
... ? ? ? ? ? ?print "foo"
...
output:
? ? ? ? ? ? <h1>
? ? ? ? ? ? foo
? ? ? ? ? ? </h1>
2.nested
with ?contextlib.nested(open('fileToRead.txt', 'r'),open('fileToWrite.txt', 'w')) as (reader, writer):
? ? ? ? writer.write(reader.read())
conetextlib.nested(..)方法有效地減少了嵌套
3.closing
from contextlib import closing
import urllib
with closing(urllib.urlopen('http://www.python.org')) as page:
? ? ? ? ?for line in page:
? ? ? ? ? ? ? ? print line
不需要明確的關閉Page.即使發生錯誤,當with 代碼塊退出時Page.close() 將被調用。