with 語句適用于對資源進行訪問的場合,確保不管使用過程中是否發生異常都會執行必要的“清理”操作,釋放資源,比如文件使用后自動關閉、線程中鎖的自動獲取和釋放等。
淺顯得講就是使用with語句,會自動幫我們在運行結束后進行清理,注意即使中途拋出異常,一樣會進行清理,有點像unitest中 teardown的意思
舉個最常見得例子:
####不使用with語句
f=open("my.log","r")
try:
lines=f.readlines()
except Exception as e:
raise e
finally:
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 enter
None
i 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
ok,到這里就結束了