Python 的 with 語句

2021-03-02 TesterHome

With語句適用於對資源進行訪問的場合,確保不管使用過程中是否發生異常都會執行必要的「清理」操作,釋放資源,比如文件使用後關閉,線程中鎖的獲取和釋放等。

術語

介紹一組與上下文管理器和with語句有關的概念。

上下文管理協議(Context Management Protocol):包含方法__enter__()和__exit__(),支持該協議的對象要實現這兩個方法。
上下文管理器(Context Manager):支持上下文管理協議的對象,定義執行with語句時要建立的運行時上下文,負責執行with語句塊上下文中的進入與退出操作。
運行時上下文(Runtime Context):由上下文管理器創建,通過上下文管理器的__enter__()和__exit__()方法實現。__enter__()方法在語句體執行之前進入運行時上下文;__exit__()在語句體執行完後從運行時上下文退出。
上下文表達式(Context Expression):with語句中關鍵字with的表達式,返回一個上下文管理器對象
語句體(With-Body):with語句下的代碼塊,在執行語句體之前會調用上下文管理器的__enter__()方法,執行完語句體之後會執行__exit__()方法。

基本語法

with語句的語法格式如下:

with context_expression [as target(s)]:    with-body

假設對一個文件進行操作,使用with語句,代碼如下:

with open(r'somefileName') as somefile:    for line in somefile:        print line        # ...more code

不管在處理文件過程中是否發生異常,都能保證with語句執行完之後關閉文件句柄。如果使用傳統的try/finally範式,則代碼如下:

somefile = open(r'somefileName')try:    for line in somefile:        print line        #...more codefinally:    somefile.close()

相比較下,採用with語句可減少代碼量。

工作原理

PEP 0343 對 with 語句的實現進行了描述。with 語句的執行過程類似如下代碼塊:

context_manager = context_expressionvalue = type(context_manager).__enter__(context_manager)exit = type(context_manager).__exit__exc = True # True 表示正常執行,即便有異常也忽略;False 表示重新拋出異常,需要對異常進行處理try:    try:        target = value # 如果使用了as子句        with-body # 執行with-body    except:    # 執行過程中有異常發生    exc = False    # 如果 __exit__ 返回 True,則異常被忽略;如果返回 False,則重新拋出異常    # 由外層代碼對異常進行處理    if not exit(context_manager, *sys.exc_info()):        raisefinally:    # 正常退出,或者通過 statement-body 中的 break/continue/return 語句退出    # 或者忽略異常退出    if exc:        exit(context_manager, None, None, None)    # 預設返回 None,None 在布爾上下文中看做是 False

執行context_expression,生成上下文管理器context_manager

調用上下文管理器的__enter__()方法;若使用了as子句,則將__enter__()方法的返回值賦值給as子句中的target(s)。target(s)是單個變量,或者是元組(必須加「()」)

執行語句體with-body

不管執行過程中是否發生異常,都會執行上下文管理器的__exit__()方法。__exit__()方法負責執行「清理」工作,如釋放資源等。若執行過程中沒有出現異常,或者語句體with-body中執行語句 break/continue/return,則以 None 作為參數調用 __exit__(None, None, None);若執行過程中出現異常,則使用 sys.exc_info 得到的異常信息為參數調用__exit__(exc_type, exc_value, exc_traceback)

執行語句體with-body出現異常,若__exit__(exc_type, exc_value, exc_traceback)返回False,則重新拋出異常,with語句之外的邏輯處理異常;若返回True,則忽略此異常,不再對異常進行處理。

自定義上下文管理器

開發人員可以自定義支持上下文管理協議的類,實現上下文管理協議所需的兩個方法:__exit__()和__exit__(exc_type, exc_value, exc_traceback)。
注意 上下文管理器必須同時提供 __enter__() 和__exit__() 方法的定義,缺少任何一個都會導致AttributeError;with 語句先檢查是否定義了 __exit__() 方法,然後檢查是否定義了__enter__()方法。
下面通過一個簡單的示例來演示如何構建自定義的上下文管理器。

class DummyResource:    def __init__(self, tag):        self.tag = tag        print('Resource[%s]' % tag)    def __enter__(self):        print('[Enter %s]: Allocate resource.' % self.tag)        return self  # 可以返回不同的對象    def __exit__(self, exc_type, exc_value, exc_tb):        print('[Exit %s]: Free resource.' % self.tag)        if exc_tb is None:            print('[Exit %s]: Exited without exception.' % self.tag)        else:            print('[Exit %s]: Exited with exception raised.' % self.tag)            return False  # 可以省略,預設的None被看作是False

使用自定義的支持with語句的對象

with DummyResource('Normal'):    print('[with-body] Run without exceptions.')

運行結果如下;

Resource[Normal][Enter Normal]: Allocate resource.[with-body] Run without exceptions.[Exit Normal]: Free resource.[Exit Normal]: Exited without exception.

正常執行時會先執行__enter__(),再執行完語句體 with-body,最後執行 __exit__()方法釋放資源。

with DummyResource('With-Exception'):    print('[with-body] Run with exception.')    raise Exception    print('[with-body] Run with exception. Failed to finish statement-body')

運行結果如下:

Resource[With-Exception][Enter With-Exception]: Allocate resource.[with-body] Run with exception.[Exit With-Exception]: Free resource.[Exit With-Exception]: Exited with exception raised.Traceback (most recent call last):  File "C:/DummyResource.py", line 23, in <module>    raise ExceptionExceptionProcess finished with exit code 1

執行with-body語句發生異常,with-body語句體未執行完畢,但資源釋放了,並拋出異常由with-body之外代碼邏輯來捕獲處理。

可以自定義上下文管理器來對軟體系統中的資源進行管理,比如資料庫連接、共享資源的訪問控制等。Python 在線文檔 Writing Context Managers 提供了一個針對資料庫連接進行管理的上下文管理器的簡單範例。

其他

特別感謝這篇文章淺談 Python 的 with 語句,讓我基本了解了with語句的用法。

相關焦點

  • Python基礎教程判斷(if)語句
    判斷(if)語句目標開發中的應用場景if 語句體驗if 語句進階綜合應用判斷語句 又被稱為 「分支語句」,正是因為有了判斷,才讓程序有了很多的分支02. if 語句體驗2.1 if 判斷語句基本語法在Python
  • python學習筆記:條件語句IF
    則執行後面的語句,而執行內容可以多行,以縮進來區分表示同一範圍。else 為可選語句,當需要在條件不成立時執行內容則可以執行相關語句': # 判斷變量是否為 python print('welcome boss') # 並輸出歡迎信息else: print(name) # 條件不成立時輸出變量名稱
  • Python 語句與結構
    1、賦值語句python 的賦值都是指對象的引用。保存的是對象的內存地址。例如PyValue=「今天天氣不錯」 PyValue=「心情也不錯」第一句執行時Python 先在內存中創建字符串對象並賦值」 今天天氣不錯」, PyValue 設置為字符串對象的引用。
  • 魅力python——if-elif-else語句
    小夥伴們大家好,今天我們一起來學習python的條件判斷——if語句。計算機能自動完成許多工作,整個過程不需要人為的參與,幹涉計算機的工作。自動化的發展,解放了人類的雙手,提高了生產力,提高了人類的生活質量。
  • python:if語句和字典
    微信公眾號:學點啥玩點啥小白友好型python:if語句和字典#第5章 if語句
  • Python每天一分鐘:pass與assert語句詳解
    今天為大家介紹的是python中兩個經典的語句:pass語句和assert語句!請注意我們這裡用的修飾詞是語句,表明其使用方式類似if,else,for等這樣的修飾語句,而不是函數。下面將為大家詳細介紹python中的pass和assert語句的功能與示例。
  • Python while循環語句詳解
    while 語句的語法格式如下:while 條件表達式:    代碼塊這裡的代碼塊,指的是縮進格式相同的多行代碼,不過在循環結構中,它又稱為循環體。while 語句執行的具體流程為:首先判斷條件表達式的值,其值為真(True)時,則執行代碼塊中的語句,當執行完畢後,再回過頭來重新判斷條件表達式的值是否為真,若仍為真,則繼續重新執行代碼塊...如此循環,直到條件表達式的值為假(False),才終止循環。while 循環結構的執行流程如圖 1 所示。
  • python循環語句for和while用法-py猜數字小遊戲-學習python第4天
    而python程序遇到循環,重複的問題時,就需要使用python循環語句for-in循環或者while循環來解決。這兩者有什麼區別以及如何使用呢?下面羽憶教程為你解答。python循環語句python循環語句在python程序中,我們總會遇到需要重複執行某條或者某些命令,例如,在屏幕中每隔一秒列印一次"python
  • Python條件語句和循環語句
    1、什麼是條件語句Python 條件語句跟其他語言基本一致的,都是通過一條或多條語句的執行結果( True 或者 False )來決定執行的代碼塊。執行的流程圖如下:2、if 語句的基本形式Python 中,if 語句的基本形式如下:if 判斷條件:執行語句……else: 執行語句
  • Python基礎-While循環語句
    1. while循環語句作用:實現特定代碼重複執行格式:while 條件: 重複執行的一行或多行代碼2. break和continuebreak作用:當循環體執行到 break 語句時就會馬上退出循環
  • Python分支結構(if條件語句)
    順序結構就是按照語句的自然先後順序進行依次執行,我們之前講解的案例基本都是順序結構,順序結構比較簡單,在此不做贅述,讓我們直接來看分支結構。    分支機構就是在Python中需要使用 if 條件語句對條件進行判斷,然後根據判斷產生的不能結構去執行不同的代碼,這種就叫分支結構(也叫選擇結構)。
  • python循環控制語句
    循環語句語句後面一定要跟:冒號for循環:1.for…in range()遍歷格式:for i in range(5);或者for i in range( 0,10,3 );格式中的1列印i是從0開始後列印到5結束
  • 柳小白Python學習筆記 7 循環語句學習
    昨天學習的是條件語句,今天開始學循環語句。在python中我們可以使用循環語句讓某個語句或代碼組多次執行。這時就會會用到for和while語句。在python中循環語句用於循環執行程序,來處理需要重複處理的任務。
  • Python中break語句用法詳解!
    這篇文章主要介紹了詳解Python中break語句的用法,是Python入門的呼出知識,需要的朋友可以參考下 在Python中的break
  • Python中switch語句怎麼用,問愣了很多人
    今天我們來聊聊switch,斷斷續續的,學習Python編程已經學習很久了,最近要用到分支語句,就習慣性的想到了,switch-case語句,這個在大部分主流程式語言中都有,如C,C++,C#,Java等等。但是作為python編程愛好者的我,竟然剛剛才發現python語言中居然沒有switch-case語句!!
  • python條件判斷語句
    python輸入語句 大家已經練習完了輸出之後呢,我們來繼續看一下輸入語句的用法 input後面加上提示輸入的語句,就可以獲取用戶輸入的語句 舉個小例子: 我們輸入123456後按回車,即可成功輸入
  • 慢步學習,python編程實例中,對遍歷程序結構for語句的解析
    大家好,慢步繼續不定期更新通俗易懂的python編程學習內容。今天主要說說for語句。for語句是比較常見的語句,其實也算比較簡單的,多看幾個實例就可以了解。但慢步還是想囉嗦一些,跟大家解析一下。第6行為引用python-docx庫內的Document模塊(python-docx庫的引用默認為docx,和庫設計有關,其他庫一般用庫名稱)。第8行,打開word文檔(123.docx),用變量d來指代打開的文檔,後面代碼中 d 就是我們這裡打開的123.docx。
  • 一起學python-認識神秘的循環語句「if」
    今天給大家分享下python中的循環語句 if 我們人的一生中會面臨著很多選擇,實際上每天每時每刻我們的大腦都在做出這樣或者那樣的選擇。下面進入程序的世界,把剛剛吃早飯的這個過程用python中的if語句來表達出來。
  • Python 中的 With 語句
    with 語句使用 「with」 語句,使代碼簡潔,處理異常也更優雅。「with語句通過封裝常用的準備工作和清除任務來簡化異常處理。」此外,它將自動關閉文件。with 語句提供了一種確保始終使用清理的方法。
  • 四、python編程基礎之循環語句:基本語法以及應用實例
    實驗目的:學習python的循環語句實驗環境:已正確安裝python3.51、循環語句的語法循環語句主要應用於多次有規律的重複操作,python中有兩種循環語句,2、循環語句的應用實例(1)利用for循環輸出2~100以內的素數(約數只有1和其本身)(2)利用while循環輸出1~100之間奇數的和3、小結循環是可以讓計算機做重複有規律任務的有效方法
  • 為什麼Python中沒有switch語句?
    作者:pydanny原文:http://www.pydanny.com/why-doesnt-python-have-switch-case.html