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

深入學(xué)習(xí)Python中的上下文管理器與else塊

 更新時(shí)間:2017年08月27日 10:01:01   作者:demon_gdy  
這篇文章主要給大家介紹了關(guān)于Python中上下文管理器與else塊的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。

前言

本文主要個(gè)大家介紹了關(guān)于Python上下文管理器與else塊的相關(guān)內(nèi)容,分享出來(lái)供大家參考學(xué)習(xí),下面話不多說(shuō)了,來(lái)一起看看詳細(xì)的介紹吧。

在開始之前,我們先來(lái)看看下面這段話:

最終,上下文管理器可能幾乎與子程序(subroutine)本身一樣重要。目前,我們只了解了上下文管理器的皮毛……Basic 語(yǔ)言有with 語(yǔ)句,而且很多語(yǔ)言都有。但是,在各種語(yǔ)言中 with 語(yǔ)句的作用不同,而且做的都是簡(jiǎn)單的事,雖然可以避免不斷使用點(diǎn)號(hào)查找屬性,但是不會(huì)做事前準(zhǔn)備和事后清理。不要覺得名字一樣,就意味著作用也一樣。with 語(yǔ)句是非常了不起的特性。

——Raymond Hettinger

雄辯的 Python 布道者

先做這個(gè),再做那個(gè):if語(yǔ)句之外的else塊

這個(gè)語(yǔ)言特性不是什么秘密,但卻沒(méi)有得到重視:else 子句不僅能在if 語(yǔ)句中使用,還能在 for、while 和 try 語(yǔ)句中使用。for/else、while/else 和 try/else 的語(yǔ)義關(guān)系緊密,不過(guò)與if/else 差別很大。起初,else 這個(gè)單詞的意思阻礙了我對(duì)這些特性的理解,但是最終我習(xí)慣了。

else 子句的行為如下:

for

  僅當(dāng) for 循環(huán)運(yùn)行完畢時(shí)(即 for 循環(huán)沒(méi)有被 break 語(yǔ)句中止)才運(yùn)行 else 塊。

while

  僅當(dāng) while 循環(huán)因?yàn)闂l件為假值而退出時(shí)(即 while 循環(huán)沒(méi)有被break 語(yǔ)句中止)才運(yùn)行 else 塊。

try

  僅當(dāng) try 塊中沒(méi)有異常拋出時(shí)才運(yùn)行 else 塊。官方文檔(https://docs.python.org/3/reference/compound_stmts.html)還指出:“else 子句拋出的異常不會(huì)由前面的 except 子句處理。”

注意:

  在所有情況下,如果異?;蛘?return、break 或 continue 語(yǔ)句導(dǎo)致控制權(quán)跳到了復(fù)合語(yǔ)句的主塊之外,else 子句也會(huì)被跳過(guò)。

  在這些語(yǔ)句中使用 else 子句通常能讓代碼更易于閱讀,而且能省去一些麻煩,不用設(shè)置控制標(biāo)志或者添加額外的 if 語(yǔ)句。

在循環(huán)中使用 else 子句的方式如下述代碼片段所示:

 for item in my_list:
  if item.flavor == 'banana':
   break
  else:
   raise ValueError('No banana flavor found!')

一開始,你可能覺得沒(méi)必要在 try/except 塊中使用 else 子句。畢竟,在下述代碼片段中,只有 dangerous_call() 不拋出異常,after_call() 才會(huì)執(zhí)行,對(duì)吧?

 try:
  dangerous_call()
  after_call()
 except OSError:
  log('OSError...')

然而,after_call() 不應(yīng)該放在 try 塊中。為了清晰和準(zhǔn)確,try 塊中應(yīng)該只拋出預(yù)期異常的語(yǔ)句。因此,像下面這樣寫更好:

 try:
  dangerous_call()
 except OSError:
  log('OSError...')
 else:
  after_call()

現(xiàn)在很明確,try 塊防守的是 dangerous_call() 可能出現(xiàn)的錯(cuò)誤,而不是 after_call() 。而且很明顯,只有 try 塊不拋出異常,才會(huì)執(zhí)行after_call() 。

上下文管理器和with塊

  上下文管理器對(duì)象存在的目的是管理 with 語(yǔ)句,就像迭代器的存在是為了管理 for 語(yǔ)句一樣。

  with 語(yǔ)句的目的是簡(jiǎn)化 try/finally 模式。這種模式用于保證一段代碼運(yùn)行完畢后執(zhí)行某項(xiàng)操作,即便那段代碼由于異常、return 語(yǔ)句或sys.exit() 調(diào)用而中止,也會(huì)執(zhí)行指定的操作。finally 子句中的代碼通常用于釋放重要的資源,或者還原臨時(shí)變更的狀態(tài)。

  上下文管理器協(xié)議包含 __enter__ 和 __exit__ 兩個(gè)方法。with 語(yǔ)句開始運(yùn)行時(shí),會(huì)在上下文管理器對(duì)象上調(diào)用 __enter__ 方法。with 語(yǔ)句運(yùn)行結(jié)束后,會(huì)在上下文管理器對(duì)象上調(diào)用 __exit__ 方法,以此扮演 finally 子句的角色。

🌰 演示把文件對(duì)象當(dāng)成上下文管理器使用

>>> with open('mirror.py') as fp: # fp綁定到打開的文件上,因?yàn)槲募腳_enter__方法返回self
...   src = fp.read(60) # 從fp中讀取一些數(shù)據(jù)
...
>>> len(src)
>>> fp # fp變量依然可以使用
<_io.TextIOWrapper name='mirror.py' mode='r' encoding='UTF-8'>
>>> fp.closed, fp.encoding # 可以讀取fp對(duì)象的屬性
(True, 'UTF-8')
>>> fp.read(60) # 但是不能在fp上執(zhí)行I/O操作,因?yàn)樵趙ith塊的結(jié)尾,調(diào)用了TextIOWrappper.__exit__方法把文件關(guān)閉了
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: I/O operation on closed file.

測(cè)試 LookingGlass 上下文管理器類

>>> from mirror import LookingGlass
>>> with LookingGlass() as what: # 上下文管理器是LookingGlass類的實(shí)例;Python在上下文管理器上調(diào)用__enter__方法,把返回結(jié)果綁定在what上
...  print('Alice, Kitty and Snowdrop') # 打印一個(gè)字符串,然后打印what變量的值
...  print(what)
...
pordwonS dna yttiK ,ecilA # 打印出的內(nèi)容是反向的
YKCOWREBBAJ
>>> what # 現(xiàn)在,with塊已經(jīng)執(zhí)行完畢,可以看出,__enter__方法返回的值,即存儲(chǔ)在what變量中的值是字符串'JABBERWOCKY'
'JABBERWOCKY'
>>> print('Back to normal.') # 輸出不在是反向的了
Back to normal.

mirror.py:LookingGlass 上下文管理器類的代碼

class LookingGlass:

 def __enter__(self):      # 除了 self 之外,Python調(diào)用__enter__方法時(shí)不竄入其他參數(shù)
  import sys
  self.original_write = sys.stdout.write # 把原來(lái)的 sys.stdout.write 方法保存在一個(gè)實(shí)例屬性中,供后面使用
  sys.stdout.write = self.reverse_write # 為 sys.stdout.write 打猴子補(bǔ)丁,替換成自己編寫的方法
  return 'JABBERWOCKY'     # 返回 'JABBERWOCKY' 字符串,這樣才有內(nèi)容存入目標(biāo)變量 what

 def reverse_write(self, text):    # 這是用于取代 sys.stdout.write 的方法,把 text 參數(shù)的內(nèi)容反轉(zhuǎn),然后調(diào)用原來(lái)的方法實(shí)現(xiàn)
  return self.original_write(text[::-1])


 def __exit__(self, exc_type, exc_val, traceback): # 如果一切正常,Python會(huì)調(diào)用__exit__方法傳入的參數(shù)是三個(gè)None,如果拋出異常,則三個(gè)參數(shù)是異常的數(shù)據(jù)
  import sys
  sys.stdout.write = self.original_write # 還原成原來(lái)的sys.studout.write方法
  if exc_type is ZeroDivisionError:  # 如果有異常,而且是 ZeroDivisionError 類型,打印一個(gè)消息
   print('Please DO NOT divide by zero!') 
   return True       # 然后返回 True,告訴解釋器,異常已經(jīng)處理

解釋器調(diào)用 __enter__ 方法時(shí),除了隱式的 self 之外,不會(huì)傳入任何參數(shù)。傳給 __exit__ 方法的三個(gè)參數(shù)列舉如下。

exc_type

  異常類(例如 ZeroDivisionError)

exc_value

  異常實(shí)例。有時(shí)會(huì)有參數(shù)傳給異常構(gòu)造方法,例如錯(cuò)誤消息,這些參數(shù)可以使用 exc_value.args 獲取

traceback

  traceback 對(duì)象

在 with 塊之外使用 LookingGlass 類

>>> from mirror import LookingGlass
>>> manager = LookingGlass() # 實(shí)例化并審查manager實(shí)例,等同于 with LookingGlass() as manager
>>> manager
<mirror.LookingGlass object at 0x2a578ac>
>>> monster = manager.__enter__() # 在上下文管理器中調(diào)用__enter__()方法,把結(jié)果存儲(chǔ)在monster中
>>> monster == 'JABBERWOCKY' # monster的值是字符串'JABBERWOCKY',打印出來(lái)的True標(biāo)識(shí)符是反向,因?yàn)橛昧撕镒友a(bǔ)丁
eurT
>>> monster
'YKCOWREBBAJ'
>>> manager
>ca875a2x0 ta tcejbo ssalGgnikooL.rorrim<
>>> manager.__exit__(None, None, None) # 調(diào)用manager.__exit__,還原成之前的stdout.write
>>> monster
'JABBERWOCKY'

contextlib模塊中的實(shí)用工具

closing

  如果對(duì)象提供了 close() 方法,但沒(méi)有實(shí)現(xiàn)__enter__/__exit__ 協(xié)議,那么可以使用這個(gè)函數(shù)構(gòu)建上下文管理器。

suppress

  構(gòu)建臨時(shí)忽略指定異常的上下文管理器。

@contextmanager

  這個(gè)裝飾器把簡(jiǎn)單的生成器函數(shù)變成上下文管理器,這樣就不用創(chuàng)建類去實(shí)現(xiàn)管理器協(xié)議了。

ContextDecorator

  這是個(gè)基類,用于定義基于類的上下文管理器。這種上下文管理器也能用于裝飾函數(shù),在受管理的上下文中運(yùn)行整個(gè)函數(shù)。

ExitStack

  這個(gè)上下文管理器能進(jìn)入多個(gè)上下文管理器。with 塊結(jié)束時(shí),ExitStack 按照后進(jìn)先出的順序調(diào)用棧中各個(gè)上下文管理器的__exit__ 方法。如果事先不知道 with 塊要進(jìn)入多少個(gè)上下文管理器,可以使用這個(gè)類。例如,同時(shí)打開任意一個(gè)文件列表中的所有文件。

使用@contextmanager

  @contextmanager 裝飾器能減少創(chuàng)建上下文管理器的樣板代碼量,因?yàn)椴挥镁帉懸粋€(gè)完整的類,定義 __enter__ 和 __exit__ 方法,而只需實(shí)現(xiàn)有一個(gè) yield 語(yǔ)句的生成器,生成想讓 __enter__ 方法返回的值。

  在使用 @contextmanager 裝飾的生成器中,yield 語(yǔ)句的作用是把函數(shù)的定義體分成兩部分:yield 語(yǔ)句前面的所有代碼在 with 塊開始時(shí)(即解釋器調(diào)用 __enter__ 方法時(shí))執(zhí)行, yield 語(yǔ)句后面的代碼在with 塊結(jié)束時(shí)(即調(diào)用 __exit__ 方法時(shí))執(zhí)行。

mirror_gen.py:使用生成器實(shí)現(xiàn)的上下文管理器

import contextlib


@contextlib.contextmanager    # 應(yīng)用 contextmanager 裝飾器
def looking_glass():
 import sys
 original_write = sys.stdout.write # 貯存原來(lái)的 sys.stdout.write 方法

 def reverse_write(text):   # 定義自定義的 reverse_write 函數(shù);在閉包中可以訪問(wèn) original_write
  original_write(text[::-1])

 sys.stdout.write = reverse_write # 把 sys.stdout.write 替換成 reverse_write
 yield 'JABBERWOCKY'     # 產(chǎn)出一個(gè)值,這個(gè)值會(huì)綁定到 with 語(yǔ)句中 as 子句的目標(biāo)變量上
 sys.stdout.write = original_write # 控制權(quán)一旦跳出 with 塊,繼續(xù)執(zhí)行 yield 語(yǔ)句之后的代碼;這里是恢復(fù)成原來(lái)的 sys. stdout.write 方法

with looking_glass() as what:   # 直接通過(guò)上下文管理器實(shí)現(xiàn)with的功能
 print('Alice, Kitty and Snowdrop')
 print(what)

print(what)

以上代碼執(zhí)行的結(jié)果為:

pordwonS dna yttiK ,ecilA
YKCOWREBBAJ
JABBERWOCKY

其實(shí),contextlib.contextmanager 裝飾器會(huì)把函數(shù)包裝成實(shí)現(xiàn)__enter__ 和 __exit__ 方法的類

這個(gè)類的 __enter__ 方法有如下作用:

  (1) 調(diào)用生成器函數(shù),保存生成器對(duì)象(這里把它稱為 gen)。

  (2) 調(diào)用 next(gen),執(zhí)行到 yield 關(guān)鍵字所在的位置。

  (3) 返回 next(gen) 產(chǎn)出的值,以便把產(chǎn)出的值綁定到 with/as 語(yǔ)句中的目標(biāo)變量上。

with 塊終止時(shí),__exit__ 方法會(huì)做以下幾件事:

  (1) 檢查有沒(méi)有把異常傳給 exc_type;如果有,調(diào)用gen.throw(exception) , 在生成器函數(shù)定義體中包含 yield 關(guān)鍵字的那一行拋出異常。

  (2) 否則,調(diào)用 next(gen) ,繼續(xù)執(zhí)行生成器函數(shù)定義體中 yield 語(yǔ)句之后的代碼。

注意:  

  上面的 🌰 有一個(gè)嚴(yán)重的錯(cuò)誤:如果在 with 塊中拋出了異常,Python 解釋器會(huì)將其捕獲,然后在 looking_glass 函數(shù)的 yield 表達(dá)式里再次拋出。但是,那里沒(méi)有處理錯(cuò)誤的代碼,因此 looking_glass 函數(shù)會(huì)中止,永遠(yuǎn)無(wú)法恢復(fù)成原來(lái)的 sys.stdout.write 方法,導(dǎo)致系統(tǒng)處于無(wú)效狀態(tài)。

mirror_gen_exc.py:基于生成器的上下文管理器,而且實(shí)現(xiàn)了異常處理

import contextlib


@contextlib.contextmanager
def looking_glass():
 import sys
 original_write = sys.stdout.write

 def reverse_write(text):
  original_write(text[::-1])

 sys.stdout.write = reverse_write
 msg = ''        #創(chuàng)建一個(gè)變量,用于保存可能出現(xiàn)的錯(cuò)誤消息;
 try:
  yield 'JABBERWOCKY'
 except ZeroDivisionError:    #處理 ZeroDivisionError 異常,設(shè)置一個(gè)錯(cuò)誤消息
  msg = 'Please DO NOT divide by zero!'
 finally:
  sys.stdout.write = original_write # 撤銷對(duì) sys.stdout.write 方法所做的猴子補(bǔ)丁
  if msg:
   print(msg)      # 如果設(shè)置了錯(cuò)誤消息,把它打印出來(lái)

注意:

  使用 @contextmanager 裝飾器時(shí),要把 yield 語(yǔ)句放在try/finally 語(yǔ)句中(或者放在 with 語(yǔ)句中),這是無(wú)法避免的,因?yàn)槲覀冇肋h(yuǎn)不知道上下文管理器的用戶會(huì)在 with 塊中做什么。

總結(jié)

以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作能帶來(lái)一定的幫助,如果有疑問(wèn)大家可以留言交流,謝謝大家對(duì)腳本之家的支持。

相關(guān)文章

  • Python PIL庫(kù)讀取設(shè)置圖像的像素內(nèi)容方法示例

    Python PIL庫(kù)讀取設(shè)置圖像的像素內(nèi)容方法示例

    這篇文章主要為大家介紹了使用Python PIL庫(kù)Image模塊中的getpixel和putpixel方法讀取設(shè)置圖像的像素內(nèi)容實(shí)例探究,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2024-01-01
  • Python使用jpype的踩坑記錄

    Python使用jpype的踩坑記錄

    Pype是一個(gè)能夠讓 python 代碼方便地調(diào)用 Java 代碼的工具,這篇文章主要來(lái)和大家分享一下Python使用jpype會(huì)踩的一些坑,希望對(duì)大家有所幫助
    2023-06-06
  • python數(shù)據(jù)結(jié)構(gòu)之圖的實(shí)現(xiàn)方法

    python數(shù)據(jù)結(jié)構(gòu)之圖的實(shí)現(xiàn)方法

    這篇文章主要介紹了python數(shù)據(jù)結(jié)構(gòu)之圖的實(shí)現(xiàn)方法,實(shí)例分析了Python圖的表示方法與常用尋路算法的實(shí)現(xiàn)技巧,需要的朋友可以參考下
    2015-07-07
  • python使用Flask操作mysql實(shí)現(xiàn)登錄功能

    python使用Flask操作mysql實(shí)現(xiàn)登錄功能

    這篇文章主要介紹了python使用Flask操作mysql實(shí)現(xiàn)登錄功能,代碼簡(jiǎn)單易懂,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2018-05-05
  • 詳解Django 時(shí)間與時(shí)區(qū)設(shè)置問(wèn)題

    詳解Django 時(shí)間與時(shí)區(qū)設(shè)置問(wèn)題

    這篇文章主要介紹了Django 時(shí)間與時(shí)區(qū)設(shè)置問(wèn)題,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2019-07-07
  • 用python進(jìn)行視頻剪輯

    用python進(jìn)行視頻剪輯

    這篇文章主要介紹了如何用python進(jìn)行視頻剪輯,幫助大家更好的利用python處理視頻,感興趣的朋友可以了解下
    2020-11-11
  • Python在Word文檔中插入圖片的三種方式

    Python在Word文檔中插入圖片的三種方式

    Word不僅僅是一個(gè)文字處理工具,它還為用戶提供了圖片插入功能,以增強(qiáng)文檔的表現(xiàn)力,一張好的圖片往往能夠起到畫龍點(diǎn)睛的作用,這篇博客將介紹使用Python在Word文檔中插入圖片的三種方式,需要的朋友可以參考下
    2025-02-02
  • Python區(qū)塊鏈交易類教程

    Python區(qū)塊鏈交易類教程

    這篇文章主要為大家介紹了Python區(qū)塊鏈交易類的示例詳解教程,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-05-05
  • python實(shí)現(xiàn)單機(jī)五子棋

    python實(shí)現(xiàn)單機(jī)五子棋

    這篇文章主要為大家詳細(xì)介紹了python實(shí)現(xiàn)單機(jī)五子棋,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-08-08
  • Django+Celery實(shí)現(xiàn)定時(shí)任務(wù)的示例

    Django+Celery實(shí)現(xiàn)定時(shí)任務(wù)的示例

    Celery是一個(gè)基于python開發(fā)的分布式任務(wù)隊(duì)列,而做python WEB開發(fā)最為流行的框架莫屬Django,本示例使用主要依賴包Django+Celery實(shí)現(xiàn)定時(shí)任務(wù),感興趣的朋友一起看看吧
    2021-06-06

最新評(píng)論

孟村| 皋兰县| 玛沁县| 治县。| 汽车| 双辽市| 商丘市| 贵港市| 蒙山县| 璧山县| 麻城市| 武宁县| 平顺县| 舟曲县| 专栏| 盐亭县| 寻乌县| 庐江县| 霍州市| 务川| 日喀则市| 隆化县| 商水县| 霸州市| 临高县| 鹿泉市| 台南县| 泰和县| 梓潼县| 嘉义县| 凉城县| 鹤山市| 鄯善县| 巩义市| 姚安县| 德令哈市| 乌审旗| 灌南县| 抚州市| 安西县| 古丈县|