中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

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

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

Python中with語句有什么用

發布時間:2021-07-05 18:24:12 來源:億速云 閱讀:219 作者:Leah 欄目:編程語言

這篇文章給大家介紹Python中with語句有什么用,內容非常詳細,感興趣的小伙伴們可以參考借鑒,希望對大家能有所幫助。

  語句體(with-body):with 語句包裹起來的代碼塊,在執行語句體之前會調用上下文管理器的 enter() 方法,執行完語句體之后會執行 exit() 方法。

  基本語法和工作原理

  with 語句的語法格式如下:

  清單 1. with 語句的語法格式

  with context_expression [as target(s)]:

  with-body

  這里 contextexpression 要返回一個上下文管理器對象,該對象并不賦值給 as 子句中的 target(s) ,如果指定了 as 子句的話,會將上下文管理器的 _enter() 方法的返回值賦值給 target(s)。target(s) 可以是單個變量,或者由“()”括起來的元組(不能是僅僅由“,”分隔的變量列表,必須加“()”)。

  Python 對一些內建對象進行改進,加入了對上下文管理器的支持,可以用于 with 語句中,比如可以自動關閉文件、線程鎖的自動獲取和釋放等。假設要對一個文件進行操作,使用 with 語句可以有如下代碼:

  清單 2. 使用 with 語句操作文件對象

  with open(r'somefileName') as somefile:

  for line in somefile:

  print line

  # ...more code

  這里使用了 with 語句,不管在處理文件過程中是否發生異常,都能保證 with 語句執行完畢后已經關閉了打開的文件句柄。如果使用傳統的 try/finally 范式,則要使用類似如下代碼:

  清單 3. try/finally 方式操作文件對象

  somefile = open(r'somefileName')

  try:

  for line in somefile:

  print line

  # ...more code

  finally:

  somefile.close()

  比較起來,使用 with 語句可以減少編碼量。已經加入對上下文管理協議支持的還有模塊 threading、decimal 等。

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

  清單 4. with 語句執行過程

  context_manager = context_expression

  exit = type(context_manager).__exit__

  value = type(context_manager).__enter__(context_manager)

  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()):

  raise

  finally:

  # 正常退出,或者通過 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)。

  執行語句體 with-body

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

  出現異常時,如果 exit(type, value, traceback) 返回 False,則會重新拋出異常,讓with 之外的語句邏輯來處理異常,這也是通用做法;如果返回 True,則忽略異常,不再對異常進行處理。

  自定義上下文管理器

  開發人員可以自定義支持上下文管理協議的類。自定義的上下文管理器要實現上下文管理協議所需要的 enter() 和 exit() 兩個方法:

  contextmanager._enter() :進入上下文管理器的運行時上下文,在語句體執行前調用。with 語句將該方法的返回值賦值給 as 子句中的 target,如果指定了 as 子句的話。

  contextmanager._exit(exc_type, exc_value, exc_traceback) :退出與上下文管理器相關的運行時上下文,返回一個布爾值表示是否對發生的異常進行處理。參數表示引起退出操作的異常,如果退出時沒有發生異常,則3個參數都為None。如果發生異常,返回。

  True 表示不處理異常,否則會在退出該方法后重新拋出異常以由 with 語句之外的代碼邏輯進行處理。如果該方法內部產生異常,則會取代由 statement-body中語句產生的異常。要處理異常時,不要顯示重新拋出異常,即不能重新拋出通過參數傳遞進來的異常,只需要將返回值設置為 False 就可以了。之后,上下文管理代碼會檢測是否 exit() 失敗來處理異常。

  下面通過一個簡單的示例來演示如何構建自定義的上下文管理器。注意,上下文管理器必須同時提供 enter() 和 exit() 方法的定義,缺少任何一個都會導致 AttributeError;with 語句會先檢查是否提供了 exit() 方法,然后檢查是否定義了 enter() 方法。

  假設有一個資源 DummyResource,這種資源需要在訪問前先分配,使用完后再釋放掉;分配操作可以放到 enter() 方法中,釋放操作可以放到 exit() 方法中。簡單起見,這里只通過打印語句來表明當前的操作,并沒有實際的資源分配與釋放。

  清單 5. 自定義支持 with 語句的對象

  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

  DummyResource 中的 enter() 返回的是自身的引用,這個引用可以賦值給 as 子句中的 target 變量;返回值的類型可以根據實際需要設置為不同的類型,不必是上下文管理器對象本身。

  exit() 方法中對變量 exctb 進行檢測,如果不為 None,表示發生了異常,返回 False 表示需要由外部代碼邏輯對異常進行處理;注意到如果沒有發生異常,缺省的返回值為 None,在布爾環境中也是被看做 False,但是由于沒有異常發生,_exit() 的三個參數都為 None,上下文管理代碼可以檢測這種情況,做正常處理。

  下面在 with 語句中訪問 DummyResource :

  清單 6. 使用自定義的支持 with 語句的對象

  with DummyResource('Normal'):

  print '[with-body] Run without exceptions.'

  with DummyResource('With-Exception'):

  print '[with-body] Run with exception.'

  raise Exception

  print '[with-body] Run with exception. Failed to finish statement-body!'

  第1個 with 語句的執行結果如下:

  清單 7. with 語句1執行結果

  Resource [Normal]

  [Enter Normal]: Allocate resource.

  [with-body] Run without exceptions.

  [Exit Normal]: Free resource.

  [Exit Normal]: Exited without exception.

  可以看到,正常執行時會先執行完語句體 with-body,然后執行 exit() 方法釋放資源。

  第2個 with 語句的執行結果如下:

  清單 8. with 語句2執行結果

  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 "G:/demo", line 20, in raise Exception

  Exception

  可以看到,with-body 中發生異常時with-body 并沒有執行完,但資源會保證被釋放掉,同時產生的異常由 with 語句之外的代碼邏輯來捕獲處理。

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

  contextlib 模塊

  contextlib 模塊提供了3個對象:裝飾器 contextmanager、函數nested和上下文管理器closing。使用這些對象,可以對已有的生成器函數或者對象進行包裝,加入對上下文管理協議的支持,避免了專門編寫上下文管理器來支持 with 語句。

  裝飾器 contextmanager

  contextmanager 用于對生成器函數進行裝飾,生成器函數被裝飾以后,返回的是一個上下文管理器,其 enter() 和 exit() 方法由 contextmanager 負責提供,而不再是之前的迭代子。被裝飾的生成器函數只能產生一個值,否則會導致異常 RuntimeError;產生的值會賦值給 as 子句中的 target,如果使用了 as 子句的話。下面看一個簡單的例子。

  清單 9. 裝飾器 contextmanager 使用示例

  from contextlib import contextmanager

  @contextmanager

  def demo():

  print '[Allocate resources]'

  print 'Code before yield-statement executes in __enter__'

  yield '*** contextmanager demo ***'

  print 'Code after yield-statement executes in __exit__'

  print '[Free resources]'

  with demo() as value:

  print 'Assigned Value: %s' % value

  結果輸出如下:

  清單 10. contextmanager 使用示例執行結果

  [Allocate resources]

  Code before yield-statement executes in __enter__

  Assigned Value: *** contextmanager demo ***

  Code after yield-statement executes in __exit__

  [Free resources]

  可以看到,生成器函數中 yield 之前的語句在 enter() 方法中執行,yield 之后的語句在 exit() 中執行,而 yield 產生的值賦給了 as 子句中的 value 變量。

  需要注意的是,contextmanager 只是省略了 enter() / exit() 的編寫,但并不負責實現資源的“獲取”和“清理”工作;“獲取”操作需要定義在 yield 語句之前,“清理”操作需要定義 yield 語句之后,這樣 with 語句在執行 enter() / exit() 方法時會執行這些語句以獲取/釋放資源,即生成器函數中需要實現必要的邏輯控制,包括資源訪問出現錯誤時拋出適當的異常。

  函數 nested

  nested 可以將多個上下文管理器組織在一起,避免使用嵌套 with 語句。

  清單 11. nested 語法

  with nested(A(), B(), C()) as (X, Y, Z):

  # with-body code here

  類似于:

  清單 12. nested 執行過程

  with A() as X:

  with B() as Y:

  with C() as Z:

  # with-body code here

  需要注意的是,發生異常后,如果某個上下文管理器的 exit() 方法對異常處理返回 False,則更外層的上下文管理器不會監測到異常。

  上下文管理器 closing

  closing 的實現如下:

  清單 13. 上下文管理 closing 實現

  class closing(object):

  # help doc here

  def __init__(self, thing):

  self.thing = thing

  def __enter__(self):

  return self.thing

  def __exit__(self, *exc_info):

  self.thing.close()

  上下文管理器會將包裝的對象賦值給 as 子句的 target 變量,同時保證打開的對象在 with-body 執行完后會關閉掉。closing 上下文管理器包裝起來的對象必須提供 close() 方法的定義,否則執行時會報 AttributeError 錯誤。

  清單 14. 自定義支持 closing 的對象

  class ClosingDemo(object):

  def __init__(self):

  self.acquire()

  def acquire(self):

  print 'Acquire resources.'

  def free(self):

  print 'Clean up any resources acquired.'

  def close(self):

  self.free()

  with closing(ClosingDemo()):

  print 'Using resources'

  結果輸出如下:

  清單 15. 自定義 closing 對象的輸出結果

  Acquire resources.

  Using resources

  Clean up any resources acquired.

  closing 適用于提供了 close() 實現的對象,比如網絡連接、數據庫連接等,也可以在自定義類時通過接口 close() 來執行所需要的資源“清理”工作。

關于Python中with語句有什么用就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。

向AI問一下細節

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

AI

博湖县| 淳安县| 廊坊市| 青田县| 电白县| 高州市| 武乡县| 台湾省| 康定县| 津市市| 霍林郭勒市| 饶阳县| 潜江市| 合水县| 鹰潭市| 武山县| 霍山县| 渝中区| 教育| 榕江县| 江陵县| 和政县| 锡林郭勒盟| 册亨县| 凉山| 平罗县| 疏附县| 彩票| 昂仁县| 新和县| 墨脱县| 东兴市| 宿州市| 永新县| 启东市| 鸡泽县| 峨眉山市| 宣恩县| 陇南市| 嘉祥县| 南宫市|