上下文管理器和else塊

 

1、if 語句以外的 else塊

  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語句也會被跳過。對象

 

2、上下文管理器和 with 塊

上下文管理器對象存在的目的是管理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對象

 

3、使用 @contextmanager

@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語句中。

相關文章
相關標籤/搜索