參考:
https://www.cnblogs.com/flashBoxer/p/9664813.html
https://blog.csdn.net/qq_37482956/article/details/100056517
gluon的一個例子:https://mxnet.incubator.apache.org/api/python/docs/_modules/mxnet/autograd.html#is_training # _RecordingStateScope 函數
with的語法
with EXPR as VAR:
BLOCK
上面的語法的僞代碼
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)
對上面的僞代碼的一個解析:
- 生成上下文管理器mgr。
- 第2,3行會檢查是否有 __exit__ 和 __enter__,沒有的化,會拋出AttributeError異常。
- 將__enter__的值賦值給value;這個時候會調用__enter__並執行,__exit__還不會執行。
- 如果語法中沒有寫 as VAR,那麼 VAR = value 就被忽略。
- 執行BLOCK內的代碼:正常結束,或者是通過break, continue, return來結束;然後執行__exit__內的代碼,__exit__的三個參數都是None,__exit__參數分別是:異常類型,異常值,追溯信息。
- 如果執行出現異常,執行except中的語句,調用__exit__時的參數就是sys.exc_info() #(exc_type, exc_value, exc_traceback)
注意:如果 __enter__ 沒有返回值,那麼 as 對象獲取的值就是None
class WithTest:
def __init__(self, filename):
self.filename=filename
def __enter__(self):
self.f = open(self.filename, 'r')
# return self.f
def __exit__(self, exc_type, exc_val, exc_tb):
self.f.close()
test = WithTest('file')
with test as t:
print ('test result: {}'.format(t))
輸出結果:
test result: None
這個例子裏面__enter__沒有返回,所以with語句裏的"as t"到的是None,修改一下上面的例子:
class WithTest:
def __init__(self, filename):
self.filename=filename
def __enter__(self):
self.f = open(self.filename, 'r')
return self.f
def __exit__(self, exc_type, exc_val, exc_tb):
self.f.close()
test = WithTest('file')
with test as t:
print ('test result: {}'.format(t))
輸出:
test result: <_io.TextIOWrapper name='skb.kc' mode='r' encoding='cp936'>
__enter__函數裏有返回值賦值給as的對象t。
正常來講,在BLOCK發生的錯誤會被傳到__exit__的參數裏,如果BLOCK代碼沒有發生錯誤,那麼傳入的三個參數就None,如果發生了錯誤,那麼傳入__exit__的參數就是:錯誤類型,錯誤值,和追溯信息,並且__exit__返回值爲False的情況下才會觸發 raise,拋出異常信息。
因此,如果在__exit__中返回True,即使BLOCK代碼出現了錯誤,但仍然不會產生異常。