Python with語句和過程抽取思想
python中的with語句使用於對資源進行訪問的場合,保證不管處理過程中是否發生錯誤或者異常都會執行規定的__exit__(“清理”)操作,釋放被訪問的資源,比如有檔案讀寫後自動關閉、執行緒中鎖的自動獲取和釋放等。
與python中with語句有關的概念有:上下文管理協議、上下文管理器、執行時上下文、上下文表達式、處理資源的程式碼段。
with語句的應用場景
程式設計中有很多操作都是配套使用的,這種配套的流程可以稱為計算過程,Python語言為這種計算過程專門設計了一種結構:with語句。比如檔案處理就是這類計算過程的典型代表。
使用with語句前後對比
沒有使用with語句之前,我們是這樣開啟一個檔案的:
try: # 1. [進入] f = open('a.txt','r',encoding="utf-8") # 2. [執行] print(f.read()) finally: if f: # 3. [退出] f.close()
python操作檔案的流程一般就是這三步:
1.[進入]用只讀方式開啟檔案
如果檔案不存在,open()函式就會丟擲一個IOError的錯誤,並且給出錯誤碼和詳細的資訊告訴你檔案不存在
2.[執行]讀取檔案內容
如果檔案開啟成功,接下來,呼叫read()方法可以一次讀取檔案的全部內容,Python把內容讀到記憶體,用一個str物件表示
3.[退出]關閉開啟的檔案
檔案使用完畢後必須關閉,因為檔案物件會佔用作業系統的資源,並且作業系統同一時間能開啟的檔案數量也是有限的
思考為什麼關閉檔案操作一定要放在finallly語句裡?
由於檔案讀寫時都有可能產生IOError,一旦出錯,後面的f.close()就不會呼叫。所以,為了保證無論是否出錯都能正確地關閉檔案,我們可以使用try ... finally來實現。
發現共性:
我們發現其實這種過程化的語句有共性,比如說在進去一個片段前
必須做某種超讚,處理工作後
又需要執行一個結束操作。比如上面的這段程式碼:
finally: if f: f.close()
就可以做一個封裝。
使用with語句後,我們是這樣開啟一個檔案的:
with open("a.txt","r",encoding="utf-8") as f: print(f.read())
這個with語句和前面的try ... finally結構是一樣的,但是程式碼更佳簡潔,並且不必呼叫f.close()方法。
with語句的執行原理
從直譯器的角度去理解with語句執行流程。
with語句的基本形式是:
with 表示式 as 變數: 語句塊
這樣的一段程式碼可以稱為一個上下文(context),在執行with語句時,直譯器會先求出表示式的值,這個值(物件)是一個上下文管理器,並且假設這個物件擁有如下類的構造方法:
def __enter__(): # 描述進入上下文的動作 pass def __exit__(): # 描述退出上下文的動作 pass
with語句在求出這個上下文管理器物件之後,自動執行進入方法
,並將這個物件的返回值賦值於 as 之後的變數,然後執行語句塊。然後在退出上下文前,自動執行物件的退出方法
。
python系統和標準庫的一些型別定義了這對操作,可以直接用於with語句。比如檔案物件就直接支援這一對操作,因此可以用在with語句的頭部。
如果你也有類似的計算過程需要抽取出來,那麼可以自定義一個類,並且包含進入、退出方法。
自定義open函式
自己實現才發現,使用裝飾器和生成器就能很好的解決這個問題,不需要用到類構造方法來實現;
import contextlib # 引入上下文管理包 @contextlib.contextmanager # 給函式引入裝飾器 def myopen(dir,mode): print("開始") f = open(dir,mode,encoding='utf-8') try: # 上文 yield f finally: # 下文 print("結束") f.close() with myopen("a.txt",'r') as fobj: # 把try中的yield中的f賦值給fobj # with會將with後面的函式中的yield賦值給fobj for i in fobj: print(i) # 等待上面的迴圈結束後,才最終執行finally的程式碼,所以這就是上下文管理
輸出:
開始 hello,我是a.txt的第1行文字。 結束
總結
開啟檔案讀寫、用pickle包完成資料的儲存、恢復的操作,都非常適合使用with語句。
pickle包的使用案例:
try: with open("phone.pickle","wb") as outf: pickle.dump("13193388105",outf) except: print("file have errow.") try: with open("phone.pickle","rb") as outf: data = pickle.load(outf) print(type(data)) print(data) except: print("file have errow.")
我總結了一下使用with語句的優點:
- 採用with語句的程式碼更簡潔
- 防止因為忘記寫f.close()而引發的錯誤
- 一個物件的操作有進入、退出過程可以抽取出來,並做成自動化執行
總結
以上所述是小編給大家介紹的Python with語句和過程抽取思想,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回覆大家的。在此也非常感謝大家對我們網站的支援!
如果你覺得本文對你有幫助,歡迎轉載,煩請註明出處,謝謝!