最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Python 中的with關(guān)鍵字使用詳解

 更新時(shí)間:2016年09月11日 08:59:53   投稿:hebedich  
這篇文章主要介紹了Python 中的with關(guān)鍵字使用詳解的相關(guān)資料,在Python中,with關(guān)鍵字是一個(gè)替你管理實(shí)現(xiàn)上下文協(xié)議對(duì)象的好東西,需要的朋友可以參考下

在 Python 2.5 中, with 關(guān)鍵字被加入。它將常用的 try ... except ... finally ... 模式很方便的被復(fù)用??匆粋€(gè)最經(jīng)典的例子:

with open('file.txt') as f:
  content = f.read()

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

再看另外一個(gè)例子。

在發(fā)起一個(gè)數(shù)據(jù)庫(kù)事務(wù)請(qǐng)求的時(shí)候,經(jīng)常會(huì)用類似這樣的代碼:

db.begin()

try:
  # do some actions
except:
  db.rollback()
  raise
finally:
  db.commit()

如果將發(fā)起事務(wù)請(qǐng)求的操作變成可以支持 with 關(guān)鍵字的,那么用像這樣的代碼就可以了:

with transaction(db):
  # do some actions

下面,詳細(xì)的說明一下 with 的執(zhí)行過程,并用兩種常用的方式實(shí)現(xiàn)上面的代碼。

with 的一般執(zhí)行過程

一段基本的 with 表達(dá)式,其結(jié)構(gòu)是這樣的:

with EXPR as VAR:
  BLOCK

其中: EXPR 可以是任意表達(dá)式; as VAR 是可選的。其一般的執(zhí)行過程是這樣的:

  1. 計(jì)算 EXPR ,并獲取一個(gè)上下文管理器。
  2. 上下文管理器的 __exit()__ 方法被保存起來用于之后的調(diào)用。
  3. 調(diào)用上下文管理器的 __enter()__ 方法。
  4. 如果 with 表達(dá)式包含 as VAR ,那么 EXPR 的返回值被賦值給 VAR 。
  5. 執(zhí)行 BLOCK 中的表達(dá)式。
  6. 調(diào)用上下文管理器的 __exit()__ 方法。如果 BLOCK 的執(zhí)行過程中發(fā)生了一個(gè)異常導(dǎo)致程序退出,那么異常的 type 、 value 和 traceback (即 sys.exc_info()的返回值 )將作為參數(shù)傳遞給 __exit()__ 方法。否則,將傳遞三個(gè) None 。

將這個(gè)過程用代碼表示,是這樣的:

mgr = (EXPR)
exit = type(mgr).__exit__ # 這里沒有執(zhí)行
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)

這個(gè)過程有幾個(gè)細(xì)節(jié):

如果上下文管理器中沒有 __enter()__ 或者 __exit()__ 中的任意一個(gè)方法,那么解釋器會(huì)拋出一個(gè) AttributeError 。
在 BLOCK 中發(fā)生異常后,如果 __exit()__ 方法返回一個(gè)可被看成是 True 的值,那么這個(gè)異常就不會(huì)被拋出,后面的代碼會(huì)繼續(xù)執(zhí)行。

接下來,用兩種方法來實(shí)現(xiàn)上面來實(shí)現(xiàn)上面的過程的吧。

實(shí)現(xiàn)上下文管理器類

第一種方法是實(shí)現(xiàn)一個(gè)類,其含有一個(gè)實(shí)例屬性 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 的執(zhí)行過程后,這個(gè)實(shí)現(xiàn)方式是很容易理解的。下面介紹的實(shí)現(xiàn)方式,其原理理解起來要復(fù)雜很多。

使用生成器裝飾器

在Python的標(biāo)準(zhǔn)庫(kù)中,有一個(gè)裝飾器可以通過生成器獲取上下文管理器。使用生成器裝飾器的實(shí)現(xiàn)過程如下:

from contextlib import contextmanager

@contextmanager
def transaction(db):
  db.begin()

  try:
    yield db
  except:
    db.rollback()
    raise
  else:
    db.commit()

第一眼上看去,這種實(shí)現(xiàn)方式更為簡(jiǎn)單,但是其機(jī)制更為復(fù)雜??匆幌缕鋱?zhí)行過程吧:

  1. Python解釋器識(shí)別到 yield 關(guān)鍵字后, def 會(huì)創(chuàng)建一個(gè)生成器函數(shù)替代常規(guī)的函數(shù)(在類定義之外我喜歡用函數(shù)代替方法)。
  2. 裝飾器 contextmanager 被調(diào)用并返回一個(gè)幫助方法,這個(gè)幫助函數(shù)在被調(diào)用后會(huì)生成一個(gè) GeneratorContextManager 實(shí)例。最終 with 表達(dá)式中的 EXPR 調(diào)用的是由 contentmanager 裝飾器返回的幫助函數(shù)。
  3. with 表達(dá)式調(diào)用 transaction(db) ,實(shí)際上是調(diào)用幫助函數(shù)。幫助函數(shù)調(diào)用生成器函數(shù),生成器函數(shù)創(chuàng)建一個(gè)生成器。
  4. 幫助函數(shù)將這個(gè)生成器傳遞給 GeneratorContextManager ,并創(chuàng)建一個(gè) GeneratorContextManager 的實(shí)例對(duì)象作為上下文管理器。
  5. with 表達(dá)式調(diào)用實(shí)例對(duì)象的上下文管理器的 __enter()__ 方法。
  6. __enter()__ 方法中會(huì)調(diào)用這個(gè)生成器的 next() 方法。這時(shí)候,生成器方法會(huì)執(zhí)行到 yield db 處停止,并將 db 作為 next() 的返回值。如果有 as VAR ,那么它將會(huì)被賦值給 VAR 。
  7. with 中的 BLOCK 被執(zhí)行。
  8. BLOCK 執(zhí)行結(jié)束后,調(diào)用上下文管理器的 __exit()__ 方法。 __exit()__ 方法會(huì)再次調(diào)用生成器的 next() 方法。如果發(fā)生 StopIteration 異常,則 pass 。
  9. 如果沒有發(fā)生異常生成器方法將會(huì)執(zhí)行 db.commit() ,否則會(huì)執(zhí)行 db.rollback() 。

再次看看上述過程的代碼大致實(shí)現(xiàn):

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

總結(jié)

Python的 with 表達(dá)式包含了很多Python特性?;c(diǎn)時(shí)間吃透 with 是一件非常值得的事情。

一些其他的例子

鎖機(jī)制

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

標(biāo)準(zhǔn)輸出重定向

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

參考資料

The Python “with” Statement by Example

PEP 343

相關(guān)文章

  • python利用xlsxwriter模塊 操作 Excel

    python利用xlsxwriter模塊 操作 Excel

    這篇文章主要介紹了python利用xlsxwriter模塊 操作 Excel,幫助大家更好的利用python處理表格,提高辦公效率,感興趣的朋友可以了解下
    2020-10-10
  • Pyhton多線程采集圖片方式

    Pyhton多線程采集圖片方式

    這篇文章主要介紹了Pyhton多線程采集圖片方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-12-12
  • Pytest實(shí)現(xiàn)setup和teardown的詳細(xì)使用詳解

    Pytest實(shí)現(xiàn)setup和teardown的詳細(xì)使用詳解

    這篇文章主要介紹了Pytest實(shí)現(xiàn)setup和teardown的詳細(xì)使用詳解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-04-04
  • Java Unsafe類實(shí)現(xiàn)原理及測(cè)試代碼

    Java Unsafe類實(shí)現(xiàn)原理及測(cè)試代碼

    這篇文章主要介紹了Java Unsafe類實(shí)現(xiàn)原理及測(cè)試代碼,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-09-09
  • 解決Python httpx 運(yùn)行過程中無限阻塞的問題

    解決Python httpx 運(yùn)行過程中無限阻塞的問題

    這篇文章主要介紹了解決Python httpx 運(yùn)行過程中無限阻塞的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-11-11
  • Python保留數(shù)據(jù)并刪除Excel單元格的函數(shù)和公式

    Python保留數(shù)據(jù)并刪除Excel單元格的函數(shù)和公式

    在分析處理Excel表格時(shí),我們可能需要使用各種公式或函數(shù)對(duì)表格數(shù)據(jù)進(jìn)行計(jì)算,從而分析出更多的信息,但在展示、分享或再利用分析結(jié)果時(shí),我們可能需要將含有公式的單元格轉(zhuǎn)換為靜態(tài)數(shù)值,本文將介紹如何使用Python代碼批量移除Excel單元格中的公式并保留數(shù)值
    2024-10-10
  • Django框架ORM數(shù)據(jù)庫(kù)操作實(shí)例詳解

    Django框架ORM數(shù)據(jù)庫(kù)操作實(shí)例詳解

    這篇文章主要介紹了Django框架ORM數(shù)據(jù)庫(kù)操作,結(jié)合實(shí)例形式詳細(xì)分析了Django框架ORM數(shù)據(jù)庫(kù)基本增刪改查與相關(guān)函數(shù)使用技巧,需要的朋友可以參考下
    2019-11-11
  • Python利用matplotlib畫出漂亮的分析圖表

    Python利用matplotlib畫出漂亮的分析圖表

    這篇文章主要介紹了Python利用matplotlib畫出漂亮的分析圖表,文章首先引入數(shù)據(jù)集展開詳情,需要的朋友可以參考一下
    2022-07-07
  • Linux RedHat下安裝Python2.7開發(fā)環(huán)境

    Linux RedHat下安裝Python2.7開發(fā)環(huán)境

    這篇文章主要為大家詳細(xì)介紹了Linux RedHat下安裝Python2.7、pip、ipython環(huán)境、eclipse和PyDev環(huán)境,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-05-05
  • Python利用py-redis實(shí)現(xiàn)分布式鎖

    Python利用py-redis實(shí)現(xiàn)分布式鎖

    隨著業(yè)務(wù)的增長(zhǎng),后端技術(shù)架構(gòu)會(huì)慢慢的從單體服務(wù)轉(zhuǎn)向多服務(wù)或者微服務(wù)的分布式架構(gòu),本文主要為大家介紹了如何利用Py-Redis實(shí)現(xiàn)簡(jiǎn)單的分布式鎖,需要的可以參考一下
    2023-08-08

最新評(píng)論

镇原县| 嘉禾县| 中牟县| 黄浦区| 玉溪市| 临汾市| 拜泉县| 文成县| 沂南县| 扎鲁特旗| 闵行区| 介休市| 凤冈县| 建瓯市| 四子王旗| 香河县| 海原县| 海宁市| 龙陵县| 桦南县| 临朐县| 无锡市| 禹城市| 江孜县| 同心县| 咸丰县| 乐至县| 自贡市| 长宁县| 甘肃省| 平山县| 三门峡市| 镇雄县| 普格县| 大埔县| 会同县| 蓬安县| 鹤峰县| 全椒县| 务川| 成都市|