Python中的with語句


ref:

https://docs.python.org/release/2.6/whatsnew/2.6.html#pep-343-the-with-statement

https://www.ibm.com/developerworks/cn/opensource/os-cn-pythonwith/

https://www.python.org/dev/peps/pep-0343/

摘自文檔:

with替代了之前在python里使用try...finally來做清理工作的方法。基本形式如下:

with expression [as variable]:
    with-block

當expression執行的時候,返回一個支持context management protocol(有__enter__(), __exit__()方法)的對象

這個對象的__enter__()方法在with-block執行運行,該方法返回的結果賦給variable(如果variable存在的話)

with-block執行之,__exit__()方法被調用,在這里可以執行清理工作

 

If BLOCK raises an exception, the __exit__(type, value, traceback)() is called with the exception details

with語句的運行過程如下:

mgr = (EXPR)
exit = type(mgr).__exit__  # Not calling it yet
value = type(mgr).__enter__(mgr)
exc = True
try:
    try:
        VAR = value  # Only if "as VAR" is present
        BLOCK
    except:
        # The exceptional case is handled here
        exc = False
        if not exit(mgr, *sys.exc_info()):
            raise
        # The exception is swallowed if exit() returns true
finally:
    # The normal and non-local-goto cases are handled here
    if exc:
        exit(mgr, None, None, None)

也就是說:

如果執行過程中沒有出現異常,或者語句體中執行了語句 break/continue/return,

則以 None 作為參數調用 __exit__(None, None, None) ;

如果執行過程中出現異常,則使用 sys.exc_info 得到的異常信息為參數調用 __exit__(exc_type, exc_value, exc_traceback)

出現異常時,如果 __exit__(type, value, traceback) 返回 False,則會重新拋出異常,讓with 之外的語句邏輯來處理異常,這也是通用做法;如果返回 True,則忽略異常,不再對異常進行處理

 

支持context management protocol的python對象有file object, threading locks variables, localcontext() fucntion in decimal module

在文檔里,有一個連接數據庫的例子(省略了部分非關鍵代碼):

class DatabaseConnection:
    # Database interface
    def cursor(self):
        "Returns a cursor object and starts a new transaction"
    def commit(self):
        "Commits current transaction"
    def rollback(self):
        "Rolls back current transaction"
    def __enter__(self):
        # Code to start a new transaction
        cursor = self.cursor()
        return cursor
    def __exit__(self, type, value, tb):
        if tb is None:
            # No exception, so commit
            self.commit()
        else:
            # Exception occurred, so rollback.
            self.rollback()
            # return False

然后就可以這樣使用了:

db_connection = DatabaseConnection()
with db_connection as cursor:
    cursor.execute('insert into ...')
    cursor.execute('delete from ...')
    # ... more operations ...

 


免責聲明!

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



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