欧美三区_成人在线免费观看视频_欧美极品少妇xxxxⅹ免费视频_a级毛片免费播放_鲁一鲁中文字幕久久_亚洲一级特黄

Python 的 with 語句詳解

系統 1613 0

一、簡介

with是從Python 2.5 引入的一個新的語法,更準確的說,是一種上下文的管理協議,用于簡化try…except…finally的處理流程。with通過__enter__方法初始化,然后在__exit__中做善后以及處理異常。對于一些需要預先設置,事后要清理的一些任務,with提供了一種非常方便的表達。

with的基本語法如下,EXPR是一個任意表達式,VAR是一個單一的變量(可以是tuple),”as VAR”是可選的。

復制代碼 代碼如下:

with EXPR as VAR:
??? BLOCK

根據PEP 343的解釋,with…as…會被翻譯成以下語句:
復制代碼 代碼如下:

mgr = (EXPR)
exit = type(mgr).__exit__? # Not calling it yet
value = type(mgr).__enter__(mgr)
exc = True
try:
??? try:
??????? VAR = value? # Only if "as VAR" is present
??????? BLOCK
??? except:
??????? # The exceptional case is handled here
??????? exc = False
??????? if not exit(mgr, *sys.exc_info()):
??????????? raise
??????? # The exception is swallowed if exit() returns true
finally:
??? # The normal and non-local-goto cases are handled here
??? if exc:
??????? exit(mgr, None, None, None)

為什么這么復雜呢?注意finally中的代碼,需要BLOCK被執行后才會執行finally的清理工作,因為當EXPR執行時拋出異常,訪問mgr.exit執行就會報AttributeError的錯誤。


二、實現方式

根據前面對with的翻譯可以看到,被with求值的對象必須有一個__enter__方法和一個__exit__方法。稍微看一個文件讀取的例子吧,注意在這里我們要解決2個問題:文件讀取異常,讀取完畢后關閉文件句柄。用try…except一般會這樣寫:

復制代碼 代碼如下:

f = open('/tmp/tmp.txt')
try:
??? for line in f.readlines():
??????? print(line)
finally:
??? f.close()

注意我們這里沒有處理文件打開失敗的IOError,上面的寫法可以正常工作,但是對于每個打開的文件,我們都要手動關閉文件句柄。如果要使用with來實現上述功能,需要需要一個代理類:
復制代碼 代碼如下:

class opened(object):

??? def __init__(self, name):
??????? self.handle = open(name)

??? def __enter__(self):
??????? return self.handle

??? def __exit__(self, type, value, trackback):
??????? self.handle.close()

with opened('/tmp/a.txt') as f:
??? for line in f.readlines():
??????? print(line)


注意我們定了一個名字叫opened的輔助類,并實現了__enter__和__exit__方法,__enter__方法沒有參數,__exit__方法的3個參數,分別代表異常的類型、值、以及堆棧信息,如果沒有異常,3個入參的值都為None。

如果你不喜歡定義class,還可以用Python標準庫提供的contextlib來實現:

復制代碼 代碼如下:

from contextlib import contextmanager

@contextmanager
def opened(name):
??? f = open(name)
??? try:
??????? yield f
??? finally:
??????? f.close()

with opened('/tmp/a.txt') as f:
??? for line in f.readlines():
??????? print(line)


使用contextmanager的函數,yield只能返回一個參數,而yield后面是處理清理工作的代碼。在我們讀取文件的例子中,就是關閉文件句柄。這里原理上和我們之前實現的類opened是相同的,有興趣的可以參考一下contextmanager的源代碼。

三、應用場景

廢話了這么多,那么到底那些場景下該使用with,有沒有一些優秀的例子?當然啦,不然這篇文章意義何在。以下摘自PEP 343。

一個確保代碼執行前加鎖,執行后釋放鎖的模板:

復制代碼 代碼如下:

@contextmanager
??? def locked(lock):
??????? lock.acquire()
??????? try:
??????????? yield
??????? finally:
??????????? lock.release()

??? with locked(myLock):
??????? # Code here executes with myLock held.? The lock is
??????? # guaranteed to be released when the block is left (even
??????? # if via return or by an uncaught exception).


數據庫事務的提交和回滾:
復制代碼 代碼如下:

@contextmanager
??????? def transaction(db):
??????????? db.begin()
??????????? try:
??????????????? yield None
??????????? except:
??????????????? db.rollback()
??????????????? raise
??????????? else:
??????????????? db.commit()

重定向stdout:
復制代碼 代碼如下:

@contextmanager
def stdout_redirected(new_stdout):
??? save_stdout = sys.stdout
??? sys.stdout = new_stdout
??? try:
??????? yield None
??? finally:
??????? sys.stdout = save_stdout

with opened(filename, "w") as f:
??? with stdout_redirected(f):
??????? print "Hello world"


注意上面的例子不是線程安全的,再多線程環境中要小心使用。


四、總結

with是對try…expect…finally語法的一種簡化,并且提供了對于異常非常好的處理方式。在Python有2種方式來實現with語法:class-based和decorator-based,2種方式在原理上是等價的,可以根據具體場景自己選擇。

with最初起源于一種block…as…的語法,但是這種語法被很多人所唾棄,最后誕生了with,關于這段歷史依然可以去參考PEP-343和PEP-340


更多文章、技術交流、商務合作、聯系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦?。?!

發表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 婷婷成人亚洲 | 奇米视频777 | 日本国产视频 | 免费一区| 日韩欧美在线视频 | 亚洲精品三级 | 91懂色 | 日本免费网站 | 欧美成人精品一区二区男人看 | 成人免费观看视频 | 青草国产超碰人人添人人碱 | 99热久久这里只精品国产9 | 日本在线亚州精品视频在线 | 超级碰在线视频 | 国产亚洲欧美视频 | 男女配种超爽免费视频 | 成年人国产网站 | 国产精品视屏 | 精品美女在线观看视频在线观看 | 成人在线视频免费 | 看特级毛片 | 一区二区在线免费观看 | 国产精品久久久久久婷婷天堂 | 久久久久成人精品 | 国产1区2区| 热伊人99re久久精品最新地 | 亚洲日本高清成人aⅴ片 | 韩国三级中文字幕hd久久精品 | 色爱影院 | 免费性生活视频 | 一个人看aaaa免费中文 | 色就是色欧美 | 黄色小视频在线看 | 精品国产不卡一区二区三区 | 欧美精品播放 | A片扒开双腿猛进入免费 | 久久精品免费 | 波多野结衣家教老师 | 欧美综合一区二区 | 91成人国产网站在线观看 | 久久精品无码一区二区日韩av |