首頁 後端開發 Python教學 Python中的with語句與上下文管理器

Python中的with語句與上下文管理器

Mar 01, 2017 pm 02:15 PM

在Python中作為上下文管理器的物件可以使用with語句,提供上下文管理器的contextlib模組的使用則是Python程式設計中的高級技巧,下面我們就來詳細整理一下Python中的with語句與上下文管理器學習總結:

0、關於上下文管理器
上下文管理器是可以在with語句中使用,擁有__enter__和__exit__方法的物件。

with manager as var:
  do_something(var)
登入後複製

相當於以下情況的簡化:

var = manager.__enter__()
try:
  do_something(var)
finally:
  manager.__exit__()
登入後複製

換言之,PEP 343中定義的上下文管理器協定允許將無聊的try...except...finally結構抽像到一個單獨的類別中,僅僅留下關注的do_something部分。

__enter__方法先被呼叫。它可以傳回賦給var的值。 as部分是可選的:如果它不出現,enter的回傳值簡單地被忽略。
with語句下的程式碼被執行。就像try子句,它們或成功執行到底,或break,continue或return,或是可以拋出異常。無論哪種情況,該區塊結束後,__exit__方法被呼叫。如果拋出異常,則異常訊息傳遞給__exit__,這將在下一章討論。通常情況下,異常可被忽略,就像在finally子句中一樣,並且將在__exit__結束後重新拋出。
比如說我們想確認一個檔案在完成寫入作業之後被立即關閉:

>>> class closing(object):
...  def __init__(self, obj):
...   self.obj = obj
...  def __enter__(self):
...   return self.obj
...  def __exit__(self, *args):
...   self.obj.close()
>>> with closing(open('/tmp/file', 'w')) as f:
...  f.write('the contents\n')
登入後複製

這裡我們確保了當with區塊退出時呼叫了f .close()。因為關閉檔案是非常常見的操作,該支援已經出現在file類別中。它有一個__exit__方法呼叫close,並且本身可作為上下文管理器。

>>> with open('/tmp/file', 'a') as f:
...  f.write('more contents\n')
登入後複製

try...finally常見的用法是釋放資源。各種不同的情況實現相似:在__enter__階段資源被獲得,在__exit__階段釋放,如果拋出異常也被傳遞。如文件操作,往往這是物件使用後的自然操作,內建支援使之方便。每一個版本,Python都在更多的地方提供支援。

1、如何使用上下文管理器:

如何開啟一個文件,並寫入"hello world"

filename="my.txt"
mode="w"
writer=open(filename,mode)
writer.write("hello world")
writer.close()
登入後複製

當發生異常時(如磁碟寫滿),就沒有機會執行第5行。當然,我們可以採用try-finally語句區塊進行包裝:

writer=open(filename,mode)
try:
  writer.write("hello world")
finally:
  writer.close()
登入後複製

#當我們進行複雜的操作時,try-finally語句就會變得醜陋,採用with語句重寫:

with open(filename,mode) as writer:
  writer.write("hello world")
登入後複製

as指涉了從open()函數傳回的內容,並且把它賦給了新值。 with完成了try-finally的任務。

2、自訂上下文管理器

with語句的作用類似try-finally,提供一個上下文機制。要應用with語句的類別,其內部必須提供兩個內建函數__enter__和__exit__。前者在主體程式碼執行前執行,後者在主體程式碼執行後執行。 as後面的變量,是在__enter__函數中傳回的。

class echo():
  def output(self):
    print "hello world"
  def __enter__(self):
    print "enter"
    return self #可以返回任何希望返回的东西
  def __exit__(self,exception_type,value,trackback):
    print "exit"
    if exception_type==ValueError:
      return True
    else:
      return Flase
 
>>>with echo as e:
  e.output()
登入後複製


輸出:

#
enter
hello world
exit
登入後複製

完備的__exit_ _函數如下:

def __exit__(self,exc_type,exc_value,exc_tb)
登入後複製

其中,exc_type:異常類型;exc_value:異常值;exc_tb:異常追蹤訊息

#當__exit__當傳回True時,異常不傳播

3、contextlib模組

contextlib模組的作用是提供更易用的上下文管理器,它是透過Generator實現的。 contextlib中的contextmanager作為裝飾器來提供一個針對函數層級的上下文管理機制,常用框架如下:

from contextlib import contextmanager
@contextmanager
def make_context():
  print 'enter'
  try:
    yield "ok"
  except RuntimeError,err:
    print 'error',err
  finally:
    print 'exit'
    
>>>with make_context() as value:
  print value
登入後複製

   
輸出為:

  enter
  ok
  exit
登入後複製

其中,yield寫入try-finally中是為了確保異常安全(能處理異常)as後的變數的值是由yield傳回。 yield前面的語句可看作程式碼區塊執行前操作,yield之後的操作可以看成在__exit__函數中的操作。

以執行緒鎖定為例:

@contextlib.contextmanager
def loudLock():
  print 'Locking'
  lock.acquire()
  yield
  print 'Releasing'
  lock.release()
 
with loudLock():
  print 'Lock is locked: %s' % lock.locked()
  print 'Doing something that needs locking'
 
#Output:
#Locking
#Lock is locked: True
#Doing something that needs locking
#Releasing
登入後複製

#4、contextlib.nested:減少巢狀

對於:

with open(filename,mode) as reader:
  with open(filename1,mode1) as writer:
    writer.write(reader.read())
登入後複製

可以透過contextlib.nested簡化:

with contextlib.nested(open(filename,mode),open(filename1,mode1)) as (reader,writer):
  writer.write(reader.read())
登入後複製

在python 2.7及以後,被一種新的語法取代:

with open(filename,mode) as reader,open(filename1,mode1) as writer:
  writer.write(reader.read())
登入後複製

5、contextlib.closing()

#file類別直接支援上下文管理器API,但有些表示開啟句柄的物件並不支持,如urllib.urlopen()傳回的物件。還有一些遺留類,使用close()方法而不支援上下文管理器API。為了確保關閉句柄,需要使用closing()為它建立一個上下文管理器(呼叫類別的close方法)。

import contextlib
class myclass():
  def __init__(self):
    print '__init__'
  def close(self):
    print 'close()'
   
with contextlib.closing(myclass()):
  print 'ok'
登入後複製

   
輸出:

__init__
ok
close()
登入後複製


######### #####更多Python中的with語句與上下文管理器相關文章請關注PHP中文網! ###
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
2 週前 By 尊渡假赌尊渡假赌尊渡假赌
倉庫:如何復興隊友
4 週前 By 尊渡假赌尊渡假赌尊渡假赌
Hello Kitty Island冒險:如何獲得巨型種子
3 週前 By 尊渡假赌尊渡假赌尊渡假赌

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

如何使用Python查找文本文件的ZIPF分佈 如何使用Python查找文本文件的ZIPF分佈 Mar 05, 2025 am 09:58 AM

如何使用Python查找文本文件的ZIPF分佈

如何在Python中下載文件 如何在Python中下載文件 Mar 01, 2025 am 10:03 AM

如何在Python中下載文件

我如何使用美麗的湯來解析HTML? 我如何使用美麗的湯來解析HTML? Mar 10, 2025 pm 06:54 PM

我如何使用美麗的湯來解析HTML?

python中的圖像過濾 python中的圖像過濾 Mar 03, 2025 am 09:44 AM

python中的圖像過濾

如何使用Python使用PDF文檔 如何使用Python使用PDF文檔 Mar 02, 2025 am 09:54 AM

如何使用Python使用PDF文檔

如何在django應用程序中使用redis緩存 如何在django應用程序中使用redis緩存 Mar 02, 2025 am 10:10 AM

如何在django應用程序中使用redis緩存

引入自然語言工具包(NLTK) 引入自然語言工具包(NLTK) Mar 01, 2025 am 10:05 AM

引入自然語言工具包(NLTK)

如何使用TensorFlow或Pytorch進行深度學習? 如何使用TensorFlow或Pytorch進行深度學習? Mar 10, 2025 pm 06:52 PM

如何使用TensorFlow或Pytorch進行深度學習?

See all articles