一、情景再現
在Python中,我們在打開文件的時候,為了代碼的健壯性,通常要考慮一些異常情況,比如:
try: ccfile = open('/path/data') content = ccfile.readlines() ccfile.close() except IOError: log.write('no data read\n')
如果文件操作出現異常,則寫一條錯誤日志;
考慮一種情況,如果文件打開成功,但readlines()調用失敗,異常處理會立即跳轉到except處執行,這樣文件關閉就沒有機會被執行到了。
一種解決辦法就是將close()語句放到finally子句中去,finally的特點是不管有無異常,都會被執行到。
try: try: ccfile = open('/path/data') content = ccfile.readlines() except IOError: log.write('no data read\n') finally ccfile.close()
或
try: try: ccfile = open('/path/data') content = ccfile.readlines() finally IOError: ccfile.close() except IOError: log.write('no data read\n')
但是上面的語句很不優雅。可以使用with語句:
with open('/etc/passwd') as f: for line in f: print(line)
二、with語句
1、with語句僅僅能對支持上下文管理協議的對象使用。支持本協議的對象
file
decimal.Context
thread.LockType
threading.Lock
threading.RLock
threading.Condition
threading.Semaphore
threading.BoundedSemaphore
2、with語句執行的解析:
with context_expr() as var:
doSomething()
- 當with語句執行時,便執行上下文表達式(context_expr)(一般為某個方法)來獲得一個上下文管理器對象,上下文管理器的職責是提供一個上下文對象,用於在with語句塊中處理細節:
- 一旦獲得了上下文對象,就會調用它的__enter__()方法,將完成with語句塊執行前的所有准備工作,如果with語句后面跟了as語句,則用__enter__()方法的返回值來賦值;
- 當with語句塊結束時,無論是正常結束,還是由於異常,都會調用上下文對象的__exit__()方法,__exit__()方法有3個參數,如果with語句正常結束,三個參數全部都是 None;如果發生異常,三個參數的值分別等於調用sys.exc_info()函數返回的三個值:類型(異常類)、值(異常實例)和跟蹤記錄(traceback),相應的跟蹤記錄對象。
- 因為上下文管理器主要作用於共享資源,__enter__()和__exit__()方法基本是完成的是分配和釋放資源的低層次工作,比如:數據庫連接、鎖分配、信號量加/減、狀態管理、文件打開/關閉、異常處理等。
3、自定義類使用with來管理
class A(object): def __enter__(self): print('__enter__() called') return self def print_hello(self): print("hello world!") def __exit__(self, e_t, e_v, t_b): print('__exit__() called') # 首先會執行__enter__方法 with A() as a: # a為__enter__的返回對象 a.print_hello() print('got instance') # 結束會執行__exit__方法
輸出結果:
__enter__() called hello world! got instance __exit__() called
三、contextlib模塊實現上下文自動管理
@contextmanager def context(): print('entering the zone') try: yield except Exception as e: print('with an error %s'%e) raise e else: print('with no error') with context(): print('----in context call------')
輸出:
entering the zone ----in context call------ with no error
來源:http://www.cnblogs.com/chenny7/p/4213447.html