Return in finally block in python context manager
我最近在python的with语句中遇到了一个奇怪的行为。我有一个代码,它使用Python的上下文管理器回滚
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | class Manager1(object): def release(self): pass # Implementation not important def rollback(self): # Rollback fails throwing an exception: raise Exception("A failure") def __enter__(self): print"ENTER1" def __exit__(self, exc_type, exc_val, exc_tb): print"EXIT1" try: self.rollback() finally: self.release() return False # The only difference here! class Manager2(object): def release(self): pass # Implementation not important def rollback(self): # Rollback fails throwing an exception: raise Exception("A failure") def __enter__(self): print"ENTER2" def __exit__(self, exc_type, exc_val, exc_tb): print"EXIT2" try: self.rollback() finally: self.release() return False # The only difference here! |
在上面的代码中,回滚失败,出现异常。我的问题是,为什么
1 2 3 4 5 6 | with Manager1() as m: pass # The Exception is NOT thrown on exit here with Manager2() as m: pass # The Exception IS thrown on exit here |
根据
If an exception is supplied, and the method wishes to suppress the
exception (i.e., prevent it from being propagated), it should return a
true value. Otherwise, the exception will be processed normally upon
exit from this method.
在我看来,在这两种情况下,出口都没有返回真值,因此在这两种情况下,不应压制例外。但是在Manager1中是这样的。有人能解释一下吗?
我使用的是python 2.7.6。
如果激活了
在manager1中,执行
只有在不引发异常的情况下,
我认为理解这一点的一个好方法是看一个独立于所有上下文管理器内容的单独示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | >>> def test (): try: print('Before raise') raise Exception() print('After raise') finally: print('In finally') print('Outside of try/finally') >>> test() Before raise In finally Traceback (most recent call last): File"<pyshell#7>", line 1, in <module> test() File"<pyshell#6>", line 4, in test raise Exception() Exception |
因此,您可以看到,当在
现在,如果您注释掉函数中的