您好,登錄后才能下訂單哦!
這篇文章運用簡單易懂的例子給大家介紹Python中如何使用with,內(nèi)容非常詳細,感興趣的小伙伴們可以參考借鑒,希望對大家能有所幫助。
在實際的編碼過程中,有時有一些任務,需要事先做一些設(shè)置,事后做一些清理,這時就需要python with出場了,with能夠?qū)@樣的需求進行一個比較優(yōu)雅的處理,最常用的例子就是對訪問文件的處理。
一般訪問文件資源時我們會這樣處理:
f = open(r'c:\test.txt', 'r') data = f.read() f.close()
這樣寫沒有錯,但是容易犯兩個毛病:
1. 如果在讀寫時出現(xiàn)異常而忘了異常處理。
2. 忘了關(guān)閉文件句柄
以下的加強版本的寫法:
f = open(r'c:\test.txt', 'r') try: data = f.read() finally: f.close()
以上的寫法就可以避免因讀取文件時異常的發(fā)生而沒有關(guān)閉問題的處理了。代碼長了一些。
但使用with有更優(yōu)雅的寫法:
with open(r'c:\test.txt', 'r') as f: data = f.read()
說明:
with后面接的對象返回的結(jié)果賦值給f。此例當中open函數(shù)返回的文件對象賦值給了f.with會自已獲取上下文件的異常信息。
with是如何做到的呢?
with后面返回的對象要求必須兩__enter__()/__exit__()這兩個方法,而文件對象f剛好是有這兩個方法的,故應用自如。
pytho中官方定義說明如下(https://docs.python.org/2/reference/datamodel.html#context-managers):
object.__enter__(self) 進入與此對象相關(guān)的運行時上下文。with語句將將此方法的返回值綁定到語句的AS子句中指定的目標(如果有設(shè)置的話) object.__exit__(self, exc_type, exc_value, traceback) 退出與此對象相關(guān)的運行時上下文。參數(shù)描述導致上下文退出的異常。如果上下文運行時沒有異常發(fā)生,那么三個參數(shù)都將置為None。 如果有異常發(fā)生,并且該方法希望抑制異常(即阻止它被傳播),則它應該返回True。否則,異常將在退出該方法時正常處理。 請注意, __exit__()方法不應該重新拋出傳入的異常,這是調(diào)用者的職責。
所謂上下文管理協(xié)議,就是咱們打開文件時常用的一種方法:with
__enter__(self):當with開始運行的時候觸發(fā)此方法的運行
__exit__(self, exc_type, exc_val, exc_tb):當with運行結(jié)束之后觸發(fā)此方法的運行
exc_type如果拋出異常,這里獲取異常的類型
exc_val如果拋出異常,這里顯示異常內(nèi)容
exc_tb如果拋出異常,這里顯示所在位置
下面舉例說明他的原理:
1. 無異常發(fā)生時的例子:
#!/user/bin/env python3 #-*- coding:utf-8 -*- class Test: def __enter__(self): print('__enter__() is call!') return self def dosomething(self): print('dosomethong!') def __exit__(self, exc_type, exc_value, traceback): print('__exit__() is call!') print(f'type:{exc_type}') print(f'value:{exc_value}') print(f'trace:{traceback}') print('__exit()__ is call!') with Test() as sample: sample.dosomething() >> __enter__() is call! dosomethong! __exit__() is call! type:None value:None trace:None __exit()__ is call!
以上的實例Text,我們注意到他帶有__enter__()/__exit__()這兩個方法,當對象被實例化時,就會主動調(diào)用__enter__()方法,任務執(zhí)行完成后就會調(diào)用__exit__()方法,另外,注意到,__exit__()方法是帶有三個參數(shù)的(exc_type, exc_value, traceback), 依據(jù)上面的官方說明:如果上下文運行時沒有異常發(fā)生,那么三個參數(shù)都將置為None, 這里三個參數(shù)由于沒有發(fā)生異常,的確是置為了None, 與預期一致。
2. 有異常發(fā)生時,會拋出異常的例子:
以下例子在上面稍做了一些修改,讓運行時產(chǎn)生異常,看看這三個參數(shù)的賦值情況:
#!/user/bin/env python3 #-*- coding:utf-8 -*- class Test: def __enter__(self): print('__enter__() is call!') return self def dosomething(self): x = 1/0 print('dosomethong!') def __exit__(self, exc_type, exc_value, traceback): print('__exit__() is call!') print(f'type:{exc_type}') print(f'value:{exc_value}') print(f'trace:{traceback}') print('__exit()__ is call!') # return True with Test() as sample: sample.dosomething() >> __enter__() is call! Traceback (most recent call last): __exit__() is call! type:<class 'ZeroDivisionError'> File "C:/Users/xxx/PycharmProjects/Test1/test.py", line 23, in <module> value:division by zero sample.dosomething() trace:<traceback object at 0x000001C08CF32F88> File "C:/Users/xxx/PycharmProjects/Test1/test.py", line 10, in dosomething __exit()__ is call! x = 1/0 ZeroDivisionError: division by zero
從結(jié)果可以看出, 在執(zhí)行到dosomethong時就發(fā)生了異常,然后將異常傳給了__exit__(), 依據(jù)上面的官方說明:如果有異常發(fā)生,并且該方法希望抑制異常(即阻止它被傳播),則它應該返回True。否則,異常將在退出該方法時正常處理。當前__exit__并沒有寫明返回True,故會拋出異常,也是合理的,但是正常來講,程序應該是不希望它拋出異常的,這也是調(diào)用者的職責,我們將再次修改__exit__, 將其返回設(shè)置為True。
3. 有異常發(fā)生時,不再拋出異常的例子:
# 在上面的例子上做點修改. #!/user/bin/env python3 #-*- coding:utf-8 -*- class Test: def __enter__(self): print('__enter__() is call!') return self def dosomething(self): x = 1/0 print('dosomethong!') def __exit__(self, exc_type, exc_value, traceback): print('__exit__() is call!') print(f'type:{exc_type}') print(f'value:{exc_value}') print(f'trace:{traceback}') print('__exit()__ is call!') return True with Test() as sample: sample.dosomething() >> __enter__() is call! __exit__() is call! type:<class 'ZeroDivisionError'> value:division by zero trace:<traceback object at 0x000001C94E592F88> __exit()__ is call!
從結(jié)果看,異常拋出被抑制了,符合預期。
關(guān)于Python中如何使用with就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。
免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。