else 子句不只能在 if 語句中使用,還能在for、while和try語句中使用。ide
(1)for :僅當 for 循環運行完畢時(即 for 循環沒有被break語句停止)才運行else 塊,函數
(2)while :僅當 while 循環由於條件爲False 而退出時(即 while 循環沒有被break語句停止)才運行else 塊spa
(3)try :僅當 try 塊中沒有異常拋出時才運行 else 塊。else子句拋出的異常不會由前面的except子句處理。code
▲ 在全部狀況下,若是異常或者return、break或continue語句致使控制權跳到了複合語句的主塊以外,else語句也會被跳過。對象
上下文管理器對象存在的目的是管理with語句,就像迭代器的存在是爲了管理for語句同樣。blog
with 語句的目的是簡化 try/finally 模式。ci
這種模式用於保證一段代碼運行完畢後執行某項操做,即使那段代碼因爲異常、return語句或sys.exit() 調用而停止,也會執行指定的操做。資源
finally 子句中代碼一般用於釋放重要的資源,或者還原臨時變動的轉態。作用域
上下文管理器協議包含 __enter__ 和 __exit__ 兩個方法。it
with語句開始運行時,會在上下文管理器對象上調用__enter__方法。
with語句結束運行時,會在上下文管理器對象上調用__exit__ 方法,以此扮演finally子句的角色。
▲ 與函數的模塊不一樣,with塊沒有定義新的做用域。
上下文管理器類代碼:
class LookingGlass: def __enter__(self): import sys self.original_write = sys.stdout.write sys.stdout.write = self.reverse_write return 'ABCDEFGHIJK' def reverse_write(self,text): self.original_write(text[::-1]) def __exit__(self, exc_type, exc_val, exc_tb): import sys sys.stdout.write = self.original_write if exc_type is ZeroDivisionError: print('Please Do not divide by zero') return True with LookingGlass() as what: print('Alice,Kitty and Snowdrop') print(what) # pordwonS dna yttiK,ecilA # KJIHGFEDCBA
__enter__方法返回的對象,存放在with語句的 as xxx對象中。
若是__exit__方法返回None,或者True以外的值,with塊中的任何異常都會向上冒泡。
傳給__exit__方法的三個參數列舉:exc_type:異常類;exc_value:異常實例;traceback:traceback對象
@contextmanager 裝飾器能減小建立上下文管理器的樣板代碼量;
由於不用編寫一個完整的類,定義__enter__和__exit__方法,而只需實現有一個yield 語句的生成器,生成想讓__enter__方法返回的值。
在使用@contextmanager 裝飾的生成器中,yield語句做用是把函數的定義體分紅兩部分:
yield語句前面的全部代碼在with塊開始時執行,yield語句後面的代碼在with塊結束時執行。
import contextlib @contextlib.contextmanager def looking_glass(): import sys original_write = sys.stdout.write def reverse_write(text): original_write(text[::-1]) sys.stdout.write = reverse_write yield 'ABCDEFGHIJK' sys.stdout.write = original_write with looking_glass() as what: print('Alice,Kitty and Snowdrop') print(what) # pordwonS dna yttiK,ecilA # KJIHGFEDCBA
▲ 若是在with塊中拋出異常,Python解釋器會將其捕獲,而後在yield表達式裏再次拋出。須要在此到處理異常。
@contextlib.contextmanager def looking_glass(): import sys original_write = sys.stdout.write def reverse_write(text): original_write(text[::-1]) sys.stdout.write = reverse_write msg = '' try: yield 'ABCDEFGHIJK' except ZeroDivisionError: msg = 'Please Do not divide by zero' finally: sys.stdout.write = original_write if msg: print(msg)
▲ 使用@contextmanager 裝飾器時,要把yield語句放在 try/finally 語句中,或者放在with語句中。