這篇文章主要介紹了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
#其中: EXPR 可以是任意表達式;as VAR 是可選的。
計算EXPR ,並取得一個上下文管理器。#呼叫上下文管理器的enter() 方法。
執行BLOCK 中的運算式。異常導致程式退出,那麼異常的type 、 value 和traceback (即sys.exc_info()的回傳值)將會作為參數傳遞給exit() 方法。
#將這個過程用程式碼表示,是這樣的:with EXPR as VAR: BLOCK
在 BLOCK 中發生異常後,如果 exit() 方法回傳一個可被看成是 True 的值,那麼這個例外就不會被拋出,後面的程式碼就會繼續執行。
實作上下文管理器類別
db 和上下文管理器所需要的方法enter() 和exit() 。
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)
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()
第一眼上看去,這種實作方式更為簡單,但其機制更為複雜。看看其執行過程:
Python解釋器辨識到yield 關鍵字後, def 會建立一個生成器
函數取代常規的函數(在類別定義之外我喜歡用函數代替方法)。
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關鍵字使用詳解的詳細內容。更多資訊請關注PHP中文網其他相關文章!