参考:
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代码出现了错误,但仍然不会产生异常。