python之with語句


一、情景再現

  在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()

  1. 當with語句執行時,便執行上下文表達式(context_expr)(一般為某個方法)來獲得一個上下文管理器對象,上下文管理器的職責是提供一個上下文對象,用於在with語句塊中處理細節:
  2. 一旦獲得了上下文對象,就會調用它的__enter__()方法,將完成with語句塊執行前的所有准備工作,如果with語句后面跟了as語句,則用__enter__()方法的返回值來賦值;
  3. 當with語句塊結束時,無論是正常結束,還是由於異常,都會調用上下文對象的__exit__()方法,__exit__()方法有3個參數,如果with語句正常結束,三個參數全部都是 None;如果發生異常,三個參數的值分別等於調用sys.exc_info()函數返回的三個值:類型(異常類)、值(異常實例)和跟蹤記錄(traceback),相應的跟蹤記錄對象。
  4. 因為上下文管理器主要作用於共享資源,__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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM