溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

python中with ... as語句的詳細講解

發(fā)布時間:2021-09-14 02:59:10 來源:億速云 閱讀:241 作者:chen 欄目:大數(shù)據(jù)

本篇內(nèi)容介紹了“python中with ... as語句的詳細講解”的有關(guān)知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領(lǐng)大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠?qū)W有所成!

說到 with 大家通??吹降膽撌沁@樣的:

示例 1

with open('courses.txt') as f:
   for i in f:
       print(i.strip())

打開一個文件,然后循環(huán)做一些事情。但是你知道為什么會有 with 嗎?我們自己是不是能夠?qū)懗隹梢宰饔迷?with 關(guān)鍵字上的對象呢?

現(xiàn)在,我們帶著上述兩個問題來說一說 with 的由來以及上下文管理器相關(guān)內(nèi)容。

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

示例1的功能我們可以使用 try/finally 模式實現(xiàn):

示例2

try:
   f = open('courses.txt')
   for i in f:
       print(i.strip())
finally:
   f.close()

try中的 except 和 else 不是必須的,這里為了簡單明了,我們只用了 finally。

對比兩個示例,我們可以看到示例1相對簡潔,這就是 with 的由來。

其實,語言中的一些特性或者說一些亮眼的特性,必然是有一個演化的過程的,我們作為后來者和使用者應該多花一些心思去思索其背后的實現(xiàn)過程,相信你會收獲更多。

那么 上下文管理器 又是什么呢?

上下文管理器協(xié)議包含 __enter__ 和 __exit__ 兩個方法。with 語句開始運行時,會在上下文管理器對象上調(diào)用 __enter__ 方法。with 語句運行結(jié)束后,會在上下文管理器對象上調(diào)用 __exit__ 方法,以此扮演 finally 子句的角色。最常見的例子是確保關(guān)閉文件對象(示例1)。

下面我們實現(xiàn)一個簡單的例子來直觀的感受一下:

class T:
   def __enter__(self):
       print('T.__enter__')
       return '我是__enter__的返回值'
   def __exit__(self, exc_type, exc_val, exc_tb):
       print('T.__exit__')

with T() as t:
   print(t)

輸出:

T.__enter__
我是__enter__的返回值
T.__exit__

示例3中實現(xiàn)了一個類T,它的對象包含了__enter__和__exit__方法,有了這兩個方法就可以使用 with 處理該對象。執(zhí)行 with 后面的表達式T()得到的是上下文管理器對象,通過as字句把對象綁定到了變量t上。

觀察輸出結(jié)果,可以看到with塊先調(diào)用了__enter__方法,在處理完內(nèi)部邏輯(print(t))之后調(diào)用了exit方法,而t其實就是__enter__方法的返回值。

當然,這個例子只是為了方便我們理解上下文管理器,下面我們看一個更有意思的例子:

示例4

obj1 = HaHa('你手機拿反了')
with obj1 as content:
   print('哈哈鏡花緣')
   print(content)
print('#### with 執(zhí)行完畢后,再輸出content: ####')
print(content)

輸出:

緣花鏡哈哈
了反拿機手你
#### with 執(zhí)行完畢后,在輸出content: ####
你手機拿反了

示例4中,上下文管理器是 HaHa 類的實例,Python 調(diào)用此實例的 __enter__ 方法,把返回結(jié)果綁定到 變量content 上。

打印一個字符串,然后打印 content 變量的值??梢钥吹酱蛴〕龅膬?nèi)容都是是反向的。

最后,當 with 塊已經(jīng)執(zhí)行完畢。可以看出,__enter__ 方法返回的值——即存儲在 content 變量中的值——是字符串 ‘你手機拿反了’。
輸出不再是反向的了。

HaHa類的實現(xiàn):

import sys

class HaHa:

   def __init__(self, word):
       self.word = word

   def reverse_write(self, text):
       self.original_write(text[::-1])

   def __enter__(self):
       self.original_write = sys.stdout.write
       sys.stdout.write = self.reverse_write
       return self.word

   def __exit__(self, exc_type, exc_value, traceback):
       sys.stdout.write = self.original_write
       return True

在__enter__方法中,我們接管了標準輸出,將其替換成我們自己編寫的方法reverse_write,reverse_write方法將參數(shù)內(nèi)容反轉(zhuǎn)。而在__exit__方法中,我們將標準輸出還原。__exit__方法需要返回True。

總之,with之于上下文管理器,就像for之于迭代器一樣。with就是為了方便上下文管理器的使用。

上下文管理器特性在標準庫中有一些應用:

  • 在 sqlite3 模塊中用于管理事務;

  • 在 threading 模塊中用于維護鎖、條件和信號;


另外,說到上下文管理器就不得不提一下@contextmanager 裝飾器,它能減少創(chuàng)建上下文管理器的樣板代碼量,因為不用編寫一個完整的類,定義 __enter__和 __exit__ 方法,而只需實現(xiàn)有一個 yield 語句的生成器,生成想讓 __enter__ 方法返回的值。

在使用 @contextmanager 裝飾的生成器中,yield 語句的作用是把函數(shù)的定義體分成兩部分:

  1. yield 語句前面的所有代碼在 with 塊開始時(即解釋器調(diào)用 __enter__ 方法時)執(zhí)行

  2.  yield 語句后面的代碼在with 塊結(jié)束時(即調(diào)用 __exit__ 方法時)執(zhí)行。

下面我們用 @contextmanager 裝飾器來實現(xiàn)一下示例4的功能:

示例5

import sys
import contextlib

@contextlib.contextmanager
def WoHa(n):
   original_write = sys.stdout.write
   def reverse_write(text):
       original_write(text[::-1])
   sys.stdout.write = reverse_write
   yield n
   sys.stdout.write =  original_write
   return True

obj1 = WoHa('你手機拿反了')
with obj1 as content:
   print('哈哈鏡花緣')
   print(content)
print('#### with 執(zhí)行完畢后,在輸出content: ####')
print(content)

輸出:

緣花鏡哈哈
了反拿機手你
#### with 執(zhí)行完畢后,在輸出content: ####
你手機拿反了

這里我們需要注意的是:代碼執(zhí)行到y(tǒng)ield時,會產(chǎn)出一個值,這個值會綁定到 with 語句中 as 子句的變量上。執(zhí)行 with 塊中的代碼時,這個函數(shù)會在yield這里暫停。此時,相當于示例4中執(zhí)行完__enter__方法。而控制權(quán)一旦跳出 with 塊(塊內(nèi)代碼執(zhí)行完畢)則繼續(xù)執(zhí)行 yield 語句之后的代碼。

@contextmanager 裝飾器優(yōu)雅且實用,把三個不同的 Python 特性結(jié)合到了一起:函數(shù)裝飾器、生成器和 with 語句。

“python中with ... as語句的詳細講解”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識可以關(guān)注億速云網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實用文章!

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI