理解Python的with語句

寫過多線程程序的人確定對各類鎖很熟悉,尤爲是下面這種代碼python

def lock_usage:
    lock.Lock()
    if(...) :
        lock.Unlock()
    return
 
    lock.Unlock()
    return

了避免形成死鎖,須要在每一個return語句以前都釋放鎖。像上面的代碼中,若是代碼的執行路徑不少,代碼中就會包含大量的unlock語句,代碼混亂仍是小事兒,若是萬一忘掉了unlock,就是個潛在的危險。除了鎖以外,包括文件描述符的關閉等涉及到資源釋放的操做都會有這種問題。
爲了解決內存泄漏的內存問題,現代的編程語言提供了垃圾回收機制。一樣爲了解決上面這種有限資源的釋放問題,不少語言都提供了一些語法特性。Python有with語句,C#有using,Go有defer。 先看解決這種問題的常規作法,使用finally編程

try:
    lock.Lock()
    ......
except:
    prcess_except()
finally:
    lock.Unlock

這麼寫使得代碼很亂,尤爲是當......處的代碼也包含有相似代碼時,會使得代碼更加混亂。再來看使用with語句後的代碼多線程

class LockContext(object):
    __init__(self, lock):
    self.lock = lock
 
    __enter__(self):
        self.Lock()
 
    __exit__(self, type, value, traceback):
        if type != None:
            process_except()
        self.Unlock()
        return false
 
with LockContext(lock) as lock:
    .......

 

這樣寫出來,代碼量雖然差很少,可是結構清晰了不少。在上面的代碼中__init__中的賦值是可選的,只要保證可以訪問到所需的變量就可。Python中的with語句中要求對象實現__enter__和__exit__函數。調用with語句時,會先分析該語句,執行__enter__函數,而後在當前suite退出時,會調用__exit__函數。__exit__函數中除了能夠作釋放資源的操做以外,同時也是異常處理的地方。若是當前suite正常退出,沒有拋出任何異常,__exit__的幾個參數均爲None。不然,則將此異常的type、value、traceback做爲參數傳遞給__exit__函數,同時,若是__exit__返回false,此異常會再次拋出,上一級代碼suite能夠繼續處理,若是__exit__返回true,那麼此異常就不會被再次拋出了編程語言

相關文章
相關標籤/搜索