with as 如何工作
with如何工作?
Python對with的處理還是很機智滴.基本思想就是with所求值的對象必須有一個__enter__()方法,一個__exit__()方法
緊跟with後面的語句被求值後,返回對象的__enter__()方法被調用,這個方法的返回值將被賦值給as後面的變量,當with後面的代碼塊全部被執行完之後,將調用前面返回對象的__exit__()方法.
下面例子可以具體說明with如何工作
class Sample: def __enter__(self): print("in __enter__") return "foo" # 返回值賦值給了"sample",所以下面代碼打印的foodef __exit__(self, exc_type, exc_val, exc_tb): print("in __exit__()") def get_sample(): return Sample() with get_sample() as sample: print("sample", sample)
運行代碼,輸出如下
in __enter__ sample foo in __exit__()
1,__enter__()方法被執行
2,__enter__()方法返回的值 - 這個例子中的"foo",賦值給變量"sample"
3,執行代碼塊,打印變量"smple"的值為"foo"
4,__exit__()方法被調用
with真正強大之處是他可以處理異常,可能你已經註意到Sample類的__exit__方法有三個參數
exc_type,exc_val,exc_tb.這些參數在異常處理中相當有用,我們開修改下代碼:
class Sample: def __enter__(self): return self def __exit__(self, exc_type, exc_val, exc_tb): print("type: ", exc_type) print("value: ", exc_val)print("trace: ", exc_tb) def do_something(self): bar = 1/0 return bar + 10 with Sample() as sample: sample.do_something()
這個例子中,wilt後面的get_sample()變成了Sample().這沒有任何關系.只要緊跟with後面的語句所返回的對象有__enter__()和__exit__()方法即可,此例中,Sample()的__enter__()方法返回新創建的Sample對象,並賦值給變量sample.
代碼執行後:
type: <class ‘ZeroDivisionError‘> value: division by zero trace: <traceback object at 0x00000192D8305108> Traceback (most recent call last): File "D:/數據管理/python全棧開發13期/網絡編程/day_39/隊列.py", line 164, in <module> sample.do_something() File "D:/數據管理/python全棧開發13期/網絡編程/day_39/隊列.py", line 160, in do_something bar = 1/0 ZeroDivisionError: division by zero
實際上,在with後面的代碼塊拋出任何異常時,__exit__()方法被執行.正如例子所示,異常拋出時,與之關聯的type,value和trace傳給__exit__()方法,因此判處的ZeroDivisionError異常被打印出來了.開發庫,清理資源,關閉文件等等操作,都可以放在__exit__()方法當中.
因此,Python的with語句時提供了一個有效的機制,讓代碼更簡練,同時在異常產生時,清理工作更簡單.
with as 如何工作