【ZZ】python with...as...用法

with從Python 2.5就有,須要from __future__ import with_statement。自python 2.6開始, 成爲默認關鍵字
在What's new in python2.6/3.0中,明確提到:
The ‘with‘ statement is a control-flow structure whose basic structure is:
with expression [as variable]:
          with-block
也就是說with是一個控制流語句,跟if/for/while/try之類的是一類的,with能夠用來簡化try finally代碼,看起來能夠比try finally更清晰。
這裏新引入了一個 "上下文管理協議"context management protocol,實現方法是爲一個類 定義__enter__和__exit__兩個函數。
with expresion as variable的執行過程是,首先執行__enter__函數,它的返回值會賦給as後面的variable,想讓它返回什麼就返回什麼,只要你知道怎麼處理就能夠了,若是不寫as variable,返回值會被忽略。
而後,開始執行with-block中的語句,不論成功失敗(好比發生異常、錯誤,設置sys.exit()),在with-block執行完成後,會執行__exit__函數。
這樣的過程其實等價於:
try:
    執行 __enter__的內容
    執行 with_block.
finally:
    執行 __exit__內容
只不過,如今把一部分代碼封裝成了__enter__函數,清理代碼封裝成__exit__函數。

 

它的原理以下:

全部實現上下文協議的對象都包含如下三種方法:

__context__() 它返回一個自我管理的上下文對象,或者一個真正意義的上下文管理器
__enter()__ 進入上下文管理器,開始迭代
當with語句結束的時候,不管是正常結束仍是拋出異常,都會執行__exit__(),該方法用於關閉資源鏈接。 python

若是有一個類包含 __enter__ 方法和 __exit__ 方法,像這樣:
class controlled_execution:
    def__enter__(self):
            set things up
            return thing
    def__exit__(self, type, value, traceback): sql

            tear things down
那麼它就能夠和with一塊兒使用,像這樣:
with controlled_execution() as thing:
        some code
 當with語句被執行的時候,python對錶達式進行求值,對求值的結果(叫作「內容守護者」)調用__enter__方法,並把__enter__方法的返回值賦給as後面的變量。而後python會執行接下來的代碼段,而且不管這段代碼幹了什麼,都會執行「內容守護者」的__exit__方法。

做爲額外的紅利,__exit__方法還可以在有exception的時候看到exception,而且壓制它或者對它作出必要的反應。要壓制exception,只須要返回一個true。好比,下面的__exit__方法吞掉了任何的TypeError,可是讓全部其餘的exceptions經過:
def__exit__(self, type, value, traceback):
        return isinstance(value, TypeError)

在Python2.5中,file object擁有__enter__和__exit__方法,前者僅僅是返回object本身,然後者則關閉這個文件
>>> f = open("x.txt")
>>> f
<open file 'x.txt', mode 'r' at 0x00AE82F0>
>>> f.__enter__()
<open file 'x.txt', mode 'r' at 0x00AE82F0>
>>> f.read(1)
'X'
>>> f.__exit__(None, None, None)
>>> f.read(1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: I/O operation on closed file
這樣要打開一個文件,處理它的內容,而且保證關閉它,你就能夠簡簡單單地這樣作:
with open("x.txt") as f:
    data = f.read()
    do something with data

個人補充:
數據庫的鏈接好像也能夠和with一塊兒使用,我在一本書上看到如下內容:
conn = sqlite.connect("somedb")
with conn:
    conn.execute("insert into sometable values (?,?)",("foo","bar"))
 在這個例子中,commit()是在全部with數據塊中的語句執行完畢而且沒有錯誤以後自動執行的,若是出現任何的異常,將執行rollback()操做,再次提示異常 數據庫

相關文章
相關標籤/搜索