亚洲免费在线-亚洲免费在线播放-亚洲免费在线观看-亚洲免费在线观看视频-亚洲免费在线看-亚洲免费在线视频

Python 的 with 語(yǔ)句詳解

系統(tǒng) 1757 0

一、簡(jiǎn)介

with是從Python 2.5 引入的一個(gè)新的語(yǔ)法,更準(zhǔn)確的說(shuō),是一種上下文的管理協(xié)議,用于簡(jiǎn)化try…except…finally的處理流程。with通過(guò)__enter__方法初始化,然后在__exit__中做善后以及處理異常。對(duì)于一些需要預(yù)先設(shè)置,事后要清理的一些任務(wù),with提供了一種非常方便的表達(dá)。

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

復(fù)制代碼 代碼如下:

with EXPR as VAR:
??? BLOCK

根據(jù)PEP 343的解釋?zhuān)瑆ith…as…會(huì)被翻譯成以下語(yǔ)句:
復(fù)制代碼 代碼如下:

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)

為什么這么復(fù)雜呢?注意finally中的代碼,需要BLOCK被執(zhí)行后才會(huì)執(zhí)行finally的清理工作,因?yàn)楫?dāng)EXPR執(zhí)行時(shí)拋出異常,訪問(wèn)mgr.exit執(zhí)行就會(huì)報(bào)AttributeError的錯(cuò)誤。


二、實(shí)現(xiàn)方式

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

復(fù)制代碼 代碼如下:

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

注意我們這里沒(méi)有處理文件打開(kāi)失敗的IOError,上面的寫(xiě)法可以正常工作,但是對(duì)于每個(gè)打開(kāi)的文件,我們都要手動(dòng)關(guān)閉文件句柄。如果要使用with來(lái)實(shí)現(xiàn)上述功能,需要需要一個(gè)代理類(lèi):
復(fù)制代碼 代碼如下:

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)


注意我們定了一個(gè)名字叫opened的輔助類(lèi),并實(shí)現(xiàn)了__enter__和__exit__方法,__enter__方法沒(méi)有參數(shù),__exit__方法的3個(gè)參數(shù),分別代表異常的類(lèi)型、值、以及堆棧信息,如果沒(méi)有異常,3個(gè)入?yún)⒌闹刀紴镹one。

如果你不喜歡定義class,還可以用Python標(biāo)準(zhǔn)庫(kù)提供的contextlib來(lái)實(shí)現(xiàn):

復(fù)制代碼 代碼如下:

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的函數(shù),yield只能返回一個(gè)參數(shù),而yield后面是處理清理工作的代碼。在我們讀取文件的例子中,就是關(guān)閉文件句柄。這里原理上和我們之前實(shí)現(xiàn)的類(lèi)opened是相同的,有興趣的可以參考一下contextmanager的源代碼。

三、應(yīng)用場(chǎng)景

廢話了這么多,那么到底那些場(chǎng)景下該使用with,有沒(méi)有一些優(yōu)秀的例子?當(dāng)然啦,不然這篇文章意義何在。以下摘自PEP 343。

一個(gè)確保代碼執(zhí)行前加鎖,執(zhí)行后釋放鎖的模板:

復(fù)制代碼 代碼如下:

@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).


數(shù)據(jù)庫(kù)事務(wù)的提交和回滾:
復(fù)制代碼 代碼如下:

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

重定向stdout:
復(fù)制代碼 代碼如下:

@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"


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


四、總結(jié)

with是對(duì)try…expect…finally語(yǔ)法的一種簡(jiǎn)化,并且提供了對(duì)于異常非常好的處理方式。在Python有2種方式來(lái)實(shí)現(xiàn)with語(yǔ)法:class-based和decorator-based,2種方式在原理上是等價(jià)的,可以根據(jù)具體場(chǎng)景自己選擇。

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


更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號(hào)聯(lián)系: 360901061

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

【本文對(duì)您有幫助就好】

您的支持是博主寫(xiě)作最大的動(dòng)力,如果您喜歡我的文章,感覺(jué)我的文章對(duì)您有幫助,請(qǐng)用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長(zhǎng)會(huì)非常 感謝您的哦!??!

發(fā)表我的評(píng)論
最新評(píng)論 總共0條評(píng)論
主站蜘蛛池模板: 国产成人免费全部网站 | 成人精品视频在线 | swag国产精品一区二区 | 99久久久国产精品免费播放器 | 成人精品一区久久久久 | 欧美猛妇色xxxxxbbbb | 亚洲精品第一区二区在线 | 国产精品亚洲专区在线播放 | 五月天婷婷在线观看高清 | 97国内免费久久久久久久久久 | www.夜夜骑.com | 中文字幕不卡在线播放 | 国产精品9999| 日本欧美成 | 国产国语高清在线视频二区 | 国产亚洲精品自在久久不卡 | www四虎影院 | 久久综合一区二区三区 | 国产美女久久久久 | 99久久精品国产一区二区三区 | 色综合色综合色综合色综合网 | 国产欧美高清 | 国产成人乱码一区二区三区在线 | 2021最新国产成人精品视频 | 伊人精品视频 | 日本中文字幕一区二区高清在线 | 99精品大学生啪啪自拍 | 久久国产视屏 | 天天射夜夜爱 | 久久精品久久精品国产大片 | 五月激激激综合网色播免费 | 青青草这里只有精品 | 四虎影视色费永久在线观看 | 97 在线播放 | 国产成人性毛片 | 四虎w345com| 成 人 黄 色 | 精品视频在线免费观看 | 欧美成人精品第一区二区三区 | 亚洲成人免费在线 | 国产精品免费入口视频 |