Python with語句和__enter__、__exit__過程抽取思想

with語句的應用場景

  編程中有不少操做都是配套使用的,這種配套的流程能夠稱爲計算過程,Python語言爲這種計算過程專門設計了一種結構:with語句。好比文件處理就是這類計算過程的典型表明。python


使用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()

就能夠作一個封裝。code

使用with語句後,咱們是這樣打開一個文件的:對象

with open("a.txt", "r", encoding="utf-8") as f:
    print(f.read())

這個with語句和前面的try ... finally結構是同樣的,可是代碼更佳簡潔,而且沒必要調用f.close()方法。內存


with語句的執行原理

從解釋器的角度去理解with語句執行流程。utf-8

with語句的基本形式是:資源

with 表達式 as 變量:
    語句塊

  這樣的一段代碼能夠稱爲一個上下文(context),在執行with語句時,解釋器會先求出表達式的值,這個值(對象)是一個上下文管理器,而且這個對象擁有以下類構造方法:

def __enter__():
        # 描述進入上下文的動做
        pass

    def __exit__():
        # 描述退出上下文的動做
        pass

with語句在求出這個上下文管理器對象以後,自動執行進入方法,並將這個對象的返回值賦值於 as 以後的變量,而後執行語句塊。而後在退出上下文前,自動執行對象的退出方法

python系統和標準庫的一些類型定義了這對操做,能夠直接用於with語句。好比文件對象就直接支持這一對操做,所以能夠用在with語句的頭部。

若是你也有相似的計算過程須要抽取出來,那麼能夠自定義一個類,而且包含進入、退出方法。


總結

打開文件讀寫、用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語句的優勢:

  1. 採用with語句的代碼更簡潔

  2. 防止由於忘記寫f.close()而引起的錯誤

  3. 一個對象的操做有進入、退出過程能夠抽取出來,並作成自動化執行


參考

《從問題到程序用Python編程和計算》

相關文章
相關標籤/搜索