python-with語句

Bacer發表於2021-09-09

with 語句適用於對資源進行訪問的場合,確保不管使用過程中是否發生異常都會執行必要的“清理”操作,釋放資源,比如檔案使用後自動關閉、執行緒中鎖的自動獲取和釋放等。

淺顯得講就是使用with語句,會自動幫我們在執行結束後進行清理,注意即使中途丟擲異常,一樣會進行清理,有點像unitest中 teardown的意思

舉個最常見得例子:

####不使用with語句f=open("my.log","r")try:
    lines=f.readlines()except Exception as e:    raise efinally:
    f.close()####使用with語句with open("my.log","r") as f:
    lines=f.readlines()

如果不適用with語句需要在我們不使用檔案得時候手動去關閉檔案,而with則不用,會自動幫我們處理,不管執行成功或者失敗

透過例子我們可以大致看出來with語句得語法格式

with context_expression [as  something]:       with-body

需要注意with語句操作得物件必須具有上下文管理器,也就是需要具有__ enter__方法,__ exit__方法

__enter __:入口方法,執行在with-body之前
__exit __:退出清理方法,執行在with-body之後

剛剛得例子雖然能說明問題,但是看得不夠直觀,我們來建立一個具有上下文管理器得物件

class my():
    def __enter__(self):
        print("i am enter")    def __exit__(self, exc_type, exc_val, exc_tb):
        print("i am exit")with my() as haha:
    print("i am with body")###輸出i am enter
i am with body
i am exit

上面得例子可以看出所有得執行過程,但是並沒有體現出在with body中出錯後會執行exit方法,來看下面得例子:

class my():
    def __enter__(self):
        print("i am enter")    def __exit__(self, exc_type, exc_val, exc_tb):
        print("i am exit")with my() as haha:
    print("i am with body"+1)###輸出i am enter
Traceback (most recent call last):
  File "/Users/hjc/workspace/myutils/meiyouyong.py", line 8, in <module>
i am exit
    print("i am with body"+1)
TypeError: must be str, not int
i am exit

可以看到exit方法被執行了,但是這裡有個bug,如果我們給my類加個成員方法,這時haha找不到該方法

class my():
    def __enter__(self):
        print("i am enter")    def __exit__(self, exc_type, exc_val, exc_tb):
        print("i am exit")    def run(self):
        print("i am run")with my() as haha:
    haha.run()###執行結果i am enter
Traceback (most recent call last):
  File "/Users/hjc/workspace/myutils/meiyouyong.py", line 10, in <module>
    haha.run()
AttributeError: 'NoneType' object has no attribute 'run'i am exit

上面得例子很明顯haha並沒有run方法,這是為什麼呢,我們再看一下下面得例子

class my():
    def __enter__(self):
        print("i am enter")    def __exit__(self, exc_type, exc_val, exc_tb):
        print("i am exit")    def run(self):
        print("i am run")with my() as haha:
    my().run()###執行結果i am enter
i am run
i am exit

我們把haha改成了my()就可以了,為什麼haha作為my()得替代沒有呢,原因是my()先執行得是enter方法,而enter並沒有返回值,導致haha替代my()時為None,自然沒有run()方法

class my():
    def __enter__(self):
        print("i am enter")    def __exit__(self, exc_type, exc_val, exc_tb):
        print("i am exit")    def run(self):
        print("i am run")with my() as haha:
    print(haha)###執行結果i am enterNonei am exit

找到問題得原因就簡單了,我們只要執行enter時候把物件返回就好了

class my():
    def __enter__(self):
        print("i am enter")        return self    #將物件返回
    def __exit__(self, exc_type, exc_val, exc_tb):
        print("i am exit")    def run(self):
        print("i am run")with my() as haha:
    haha.run()###執行結果i am enter
i am run
i am exit



作者:MR_Hanjc
連結:


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/2768/viewspace-2819030/,如需轉載,請註明出處,否則將追究法律責任。

相關文章