上下文管理器和 else 塊

小小樑發表於2019-02-16

上下文管理器

最終,上下文管理器可能幾乎與子程式(subroutine)本身一樣重要。

在各種語言中 with 語句的作用不同,而且做的都是簡單的事,雖然可以避免不
斷使用點號查詢屬性,但是不會做事前準備和事後清理。

if語句之外的else塊

else太個性了, 其他語言不同用 不用這個

兩個風格

EAFP 這種就得看好哪個else語句了

  取得原諒比獲得許可容易(easier to ask for forgiveness than permission)。這是一
種常見的 Python 程式設計風格,先假定存在有效的鍵或屬性,如果假定不成立,那麼捕
獲異常。這種風格簡單明快,特點是程式碼中有很多 try 和 except 語句。與其他很多
語言一樣(如 C 語言),這種風格的對立面是 LBYL 風格。
接下來,詞彙表定義了 LBYL。

LBYL 先用這個吧

  三思而後行(look before you leap)。這種程式設計風格在呼叫函式或查詢屬性或鍵
之前顯式測試前提條件。與 EAFP 風格相反,這種風格的特點是程式碼中有很多 if 語
句。在多執行緒環境中,LBYL 風格可能會在“檢查”和“行事”的空當引入條件競爭。例
如,對 if key in mapping: return mapping[key] 這段程式碼來說,如果在測試
之後,但在查詢之前,另一個執行緒從對映中刪除了那個鍵,那麼這段程式碼就會失敗。
這個問題可以使用鎖或者 EAFP 風格解決。

上下文管理器和with塊

上下文管理器協議包含 enterexit 兩個方法。with 語句開始執行時,會在上下文管理器物件上呼叫 enter 方法。

with 語句執行結束後,會在上下文管理器物件上呼叫 exit 方法,以此扮演 finally 子句的角色。

class LookingGlass:
    def __enter__(self):
        import sys
        self.original_write = sys.stdout.write
        sys.stdout.write = self.reverse_write
        return `JABBERWOCKY`

    def reverse_write(self, text):
        self.original_write(text[::-1])

    def __exit__(self, exc_type, exc_value, traceback):
        import sys
        sys.stdout.write = self.original_write
        if exc_type is ZeroDivisionError:
            print(`Please DO NOT divide by zero!`)
        return True

❻ 如果一切正常,Python 呼叫 exit 方法時傳入的引數是 None, None, None;如
果丟擲了異常,這三個引數是異常資料,如下所述。

直譯器呼叫 enter 方法時,除了隱式的 self 之外,不會傳入任何引數。傳給
exit 方法的三個引數列舉如下。

exc_type
異常類(例如 ZeroDivisionError)。

exc_value
  異常例項。有時會有引數傳給異常構造方法,例如錯誤訊息,這些引數可以使用exc_value.args 獲取。

traceback
  traceback 物件。

@contextmanager 裝飾器 哥還是寫全的吧

能減少建立上下文管理器的樣板程式碼量,因為不用編寫一個完整的類,定義 enterexit 方法,

而只需實現有一個 yield 語句的生成器,生成想讓 enter 方法返回的值。

總結

else 不要用python哪個沒朋友的 神奇else (不過要看懂)
上下文 with

def __enter__(self): 一般返回 self自己

def __exit__(self, exc_type, exc_value, traceback):

exc_type
異常類(例如 ZeroDivisionError)。

exc_value
  異常例項。有時會有引數傳給異常構造方法,例如錯誤訊息,這些引數可以使用exc_value.args 獲取。

traceback
  traceback 物件。

相關文章