日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > python >内容正文

python

python中为什么推荐使用with_Python中的with关键字使用详解

發布時間:2025/3/11 python 20 豆豆
生活随笔 收集整理的這篇文章主要介紹了 python中为什么推荐使用with_Python中的with关键字使用详解 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

這篇文章主要介紹了Python 中的with關鍵字使用詳解的相關資料,在Python中,with關鍵字是一個替你管理實現上下文協議對象的好東西,需要的朋友可以參考下

">

在 Python 2.5 中, with 關鍵字被加入。它將常用的 try ... except ... finally ... 模式很方便的被復用。看一個最經典的例子:with open('file.txt') as f:

content = f.read()

在這段代碼中,無論 with 中的代碼塊在執行的過程中發生任何情況,文件最終都會被關閉。如果代碼塊在執行的過程中發生了一個異常,那么在這個異常被拋出前,程序會先將被打開的文件關閉。

再看另外一個例子。

在發起一個數據庫事務請求的時候,經常會用類似這樣的代碼:db.begin()

try:

# do some actions

except:

db.rollback()

raise

finally:

db.commit()

如果將發起事務請求的操作變成可以支持 with 關鍵字的,那么用像這樣的代碼就可以了:with transaction(db):

# do some actions

下面,詳細的說明一下 with 的執行過程,并用兩種常用的方式實現上面的代碼。

with 的一般執行過程

一段基本的 with 表達式,其結構是這樣的:with EXPR as VAR:

BLOCK

其中: EXPR 可以是任意表達式; as VAR 是可選的。其一般的執行過程是這樣的:計算 EXPR ,并獲取一個上下文管理器。

上下文管理器的 exit() 方法被保存起來用于之后的調用。

調用上下文管理器的 enter() 方法。

如果 with 表達式包含 as VAR ,那么 EXPR 的返回值被賦值給 VAR 。

執行 BLOCK 中的表達式。

調用上下文管理器的 exit() 方法。如果 BLOCK 的執行過程中發生了一個異常導致程序退出,那么異常的 type 、 value 和 traceback (即 sys.exc_info()的返回值 )將作為參數傳遞給 exit() 方法。否則,將傳遞三個 None 。

將這個過程用代碼表示,是這樣的:mgr = (EXPR)

exit = type(mgr).exit # 這里沒有執行

value = type(mgr).enter(mgr)

exc = True

try:

try:

VAR = value # 如果有 as VAR

BLOCK

except:

exc = False

if not exit(mgr, *sys.exc_info()):

raise

finally:

if exc:

exit(mgr, None, None, None)

這個過程有幾個細節:

如果上下文管理器中沒有 enter() 或者 exit() 中的任意一個方法,那么解釋器會拋出一個 AttributeError 。

在 BLOCK 中發生異常后,如果 exit() 方法返回一個可被看成是 True 的值,那么這個異常就不會被拋出,后面的代碼會繼續執行。

接下來,用兩種方法來實現上面來實現上面的過程的吧。

實現上下文管理器類

第一種方法是實現一個類,其含有一個實例屬性 db 和上下文管理器所需要的方法 enter() 和 exit() 。class transaction(object):

def init(self, db):

self.db = db

def enter(self):

self.db.begin()

def exit(self, type, value, traceback):

if type is None:

db.commit()

else:

db.rollback()

了解 with 的執行過程后,這個實現方式是很容易理解的。下面介紹的實現方式,其原理理解起來要復雜很多。

使用生成器裝飾器

在Python的標準庫中,有一個裝飾器可以通過生成器獲取上下文管理器。使用生成器裝飾器的實現過程如下:from contextlib import contextmanager

@contextmanager

def transaction(db):

db.begin()

try:

yield db

except:

db.rollback()

raise

else:

db.commit()

第一眼上看去,這種實現方式更為簡單,但是其機制更為復雜。看一下其執行過程吧:Python解釋器識別到 yield 關鍵字后, def 會創建一個生成器函數替代常規的函數(在類定義之外我喜歡用函數代替方法)。

裝飾器 contextmanager 被調用并返回一個幫助方法,這個幫助函數在被調用后會生成一個 GeneratorContextManager 實例。最終 with 表達式中的 EXPR 調用的是由 contentmanager 裝飾器返回的幫助函數。

with 表達式調用 transaction(db) ,實際上是調用幫助函數。幫助函數調用生成器函數,生成器函數創建一個生成器。

幫助函數將這個生成器傳遞給 GeneratorContextManager ,并創建一個 GeneratorContextManager 的實例對象作為上下文管理器。

with 表達式調用實例對象的上下文管理器的 enter() 方法。

enter() 方法中會調用這個生成器的 next() 方法。這時候,生成器方法會執行到 yield db 處停止,并將 db 作為 next() 的返回值。如果有 as VAR ,那么它將會被賦值給 VAR 。

with 中的 BLOCK 被執行。

BLOCK 執行結束后,調用上下文管理器的 exit() 方法。 exit() 方法會再次調用生成器的 next() 方法。如果發生 StopIteration 異常,則 pass 。

如果沒有發生異常生成器方法將會執行 db.commit() ,否則會執行 db.rollback() 。

再次看看上述過程的代碼大致實現:def contextmanager(func):

def helper(*args, **kwargs):

return GeneratorContextManager(func(*args, **kwargs))

return helper

class GeneratorContextManager(object):

def init(self, gen):

self.gen = gen

def enter(self):

try:

return self.gen.next()

except StopIteration:

raise RuntimeError("generator didn't yield")

def exit(self, type, value, traceback):

if type is None:

try:

self.gen.next()

except StopIteration:

pass

else:

raise RuntimeError("generator didn't stop")

else:

try:

self.gen.throw(type, value, traceback)

raise RuntimeError("generator didn't stop after throw()")

except StopIteration:

return True

except:

if sys.exc_info()[1] is not value:

raise

總結

Python的 with 表達式包含了很多Python特性。花點時間吃透 with 是一件非常值得的事情。

一些其他的例子

鎖機制@contextmanager

def locked(lock):

lock.acquired()

try:

yield

finally:

lock.release()

標準輸出重定向@contextmanager

def stdout_redirect(new_stdout):

old_stdout = sys.stdout

sys.stdout = new_stdout

try:

yield

finally:

sys.stdout = old_stdout

with open("file.txt", "w") as f:

with stdout_redirect(f):

print "hello world"

總結

以上是生活随笔為你收集整理的python中为什么推荐使用with_Python中的with关键字使用详解的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 久久久久人妻一道无码AV | 天天干天天搞天天射 | 天堂免费在线视频 | 国产精品毛片一区二区在线看舒淇 | 波多野结衣久久精品 | 91欧美一区二区 | 国产九九九九 | 美女视频黄a视频全免费观看 | 日韩五月天 | 无码无遮挡又大又爽又黄的视频 | 黄色网址你懂得 | 肉嫁高柳在线 | 国产a v一区二区三区 | 免费黄色av网站 | 操处女逼视频 | 亚州国产精品视频 | 亚洲 欧美 日韩 在线 | 17c一起操| 超碰97干| 欧美日韩午夜激情 | 色欲色香天天天综合网www | 精品久久999 | 91青青视频 | 91麻豆国产视频 | 国产精品久久国产精麻豆96堂 | 国产精品宾馆在线 | 久久亚洲欧洲 | 国产女人水真多18毛片18精品 | 人妻中文字幕一区二区三区 | 亚洲第九十七页 | 中文字幕人妻无码系列第三区 | 人妻无码中文字幕免费视频蜜桃 | 亚洲色成人www永久网站 | 亚洲天天影视 | 伊人网亚洲 | 日韩精品字幕 | 综合精品在线 | 日本a∨视频 | 日韩午夜剧场 | 婷婷五月综合缴情在线视频 | av观看一区| 在线黄色网 | 在线观看网站污 | 99精品久久久久久久 | 春色av | 亚洲网站免费观看 | 日韩欧美国产高清 | 久久久精品日本 | 欧美精品一二三区 | 国产精品日韩电影 | 麻豆一区二区三区四区 | a级全黄 | 国产一区二区在线不卡 | 少妇精品无码一区二区三区 | 欧美一级全黄 | 久久久久高清 | 在线免费观看亚洲视频 | 九九热在线精品 | 噼里啪啦国语电影 | 欧美久久精品一级黑人c片 1000部多毛熟女毛茸茸 | 国内偷拍一区二区 | 免费观看美女裸体网站 | 成人私密视频 | 色婷婷av一区二区三区大白胸 | 91亚洲免费 | 9999热视频 | 日韩免费电影一区 | jizzjizz中国精品麻豆 | 老鸭窝av在线 | 四虎最新网址在线观看 | 亚洲a人| 美女又爽又黄免费视频 | 国产精伦 | 日本丰满熟妇hd | 欧美另类一区二区 | 韩国一区在线 | 五月婷婷久久久 | 亚洲大逼 | 春物催眠 | 91丨porny丨尤物 | 免费成人毛片 | 国产十八熟妇av成人一区 | 国产精品无码无卡无需播放器 | 奇米影视大全 | 椎名由奈av一区二区三区 | 欧美精品国产 | 欧洲综合视频 | 日本三级全黄 | 夜夜骑夜夜 | 国产精品-区区久久久狼 | 国产福利免费在线观看 | 性欧美丰满熟妇xxxx性 | 激情开心站 | 日韩一区二区三区高清 | 国产精品一区二区三区四区视频 | 最新中文字幕av | 熟女人妻aⅴ一区二区三区60路 | 国产波霸爆乳一区二区 | 日韩中文字幕视频 |