我最近在Python的with语句中遇到了一个奇怪的行为。我有一段代码,它使用Python的上下文管理器来回滚__exit__
方法中的配置更改。管理器在__exit__
中的finally块中有一个return False
值。我在下面的代码中隔离了这种情况—唯一的区别是return语句的缩进:
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!
在上面的代码中,回滚失败,出现异常。我的问题是,为什么Manager1
的行为与Manager2
不同。异常不会在Manager1
中的with语句之外引发,以及在Manager2
中退出时引发异常的原因。在
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.
在我看来,在这两种情况下,退出都不返回True,因此在这两种情况下都不应取消该异常。但在Manager1中却是如此。有人能解释一下吗?在
我使用python2.7.6。在
我认为理解这一点的一个好方法是看一个独立于所有上下文管理器的单独示例:
因此您可以看到,当异常在
try
块中抛出时,之前的任何代码都将被执行,finally
块中的任何代码都将被执行。除此之外,其他的都被跳过了。这是因为抛出的异常结束了函数调用。但是由于异常是在try
块中引发的,因此相应的finally
块有最后一次运行的机会。在现在,如果您注释掉函数中的
raise
行,您将看到所有代码都已执行,因为函数不会过早结束。在如果
finally
子句被激活,这意味着try
块已经成功完成,或者它引发了一个已被处理的错误,或者try
块执行了return
。在在Manager1中,执行
return
语句作为finally
子句的一部分,使其正常终止,返回False
。在Manager2类中,finally子句仍在执行,但如果它是由于引发异常而执行的,则它不会阻止异常在调用链上传播,直到被捕获(或直到它通过回溯终止程序)。在Manager2.__exit__()
只有在没有引发异常的情况下才会返回False。在相关问题 更多 >
编程相关推荐