上下文管理器
最終,上下文管理器可能幾乎與子程式(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塊
上下文管理器協議包含 enter 和 exit 兩個方法。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 裝飾器 哥還是寫全的吧
能減少建立上下文管理器的樣板程式碼量,因為不用編寫一個完整的類,定義 enter 和 exit 方法,
而只需實現有一個 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 物件。