这是Debian Squeeze上的Python 2.6.6(默认)。考虑下面的Python代码。在主程序或清理过程中发生错误时的异常处理
import sys
try:
raise Exception("error in main")
pass
except:
exc_info = sys.exc_info()
finally:
try:
print "cleanup - always run"
raise Exception("error in cleanup")
except:
import traceback
print >> sys.stderr, "Error in cleanup"
traceback.print_exc()
if 'exc_info' in locals():
raise exc_info[0], exc_info[1], exc_info[2]
print "exited normally"
得到的误差是
Error in cleanup
Traceback (most recent call last):
File "<stdin>", line 10, in <module>
Exception: error in cleanup
cleanup - always run
Traceback (most recent call last):
File "<stdin>", line 3, in <module>
Exception: error in main
我们的想法是,以应付的情况下或者某些代码或代码的清理(总是运行)或两者,给出了一个错误。对此有一些讨论,例如,Ian Bicking在Re-raising Exceptions。在这篇文章的最后(见Update:
),他描述了如何处理类似的代码+回滚/回复(仅在出错时运行)。
我摆弄这个,想出了上面的代码,这是一个怪胎。特别是,如果只有 清除(注释掉raise Exception("error in main")
)中的错误,但代码仍然正常退出,但它确实打印出了回溯。目前,我正在给予非清理错误优先级,所以它会停止程序。
理想情况下,我想要任何错误停止该程序,但这似乎并不容易安排。 Python似乎只想提出一个错误,如果有的话会丢失其他错误,默认情况下它通常是最后一个错误。重新排列这会产生像上面那样的卷积。
另外使用locals()
有点难看。一个人能做得更好吗?
编辑:srgerg's answer向我介绍了上下文管理器和with
关键字的概念。除了PEP 343之外,我找到的其他相关文档都是(无特定顺序)。 Context Manager Types,The with statement和http://docs.python.org/reference/datamodel.html#context-managers。这对于以前的方法来说似乎是一个很大的改进,即涉及trys,excepts和finallys的意大利面代码。
总而言之,我想要这样的解决方案给我两件事。
在其轨道到停止程序的能力为在任一主代码或在 清理异常。上下文管理器执行此操作,因为如果with循环的主体出现异常并且主体 出口没有,则会传播该异常。 如果退出抛出一个异常,并且with循环的主体没有, 然后传播。如果两者都抛出异常,则出口 异常被传播,并且来自while循环体的一个被抑制,即 。这全部记录在案,即从 Context Manager Types,
contextmanager。 exit(exc_type,exc_val,exc_tb)
退出运行环境并返回一个布尔标志,指示是否应该抑制发生的任何异常。 [...] 从此方法返回真值将导致with语句抑制异常,并在with语句后立即继续执行 语句。否则,此方法执行完毕 后异常继续传播。在执行此方法期间发生的异常将替换发生在
语句正文中的任何异常。 [...]通过的例外不应该明确重新考虑。相反,此方法应返回一个假值为 ,表示该方法已成功完成,并且不希望抑制引发的异常。如果在这两个地方例外,我希望看到回溯从两个 ,即使在技术上只有一个异常被抛出。这是真正的 基于实验的,因为如果两个抛出一个异常, 那么出口异常传播,但是从while循环体 回溯仍印刷,如 srgerg's answer。 但是,我无法在任何地方找到此记录的 ,这是不令人满意的。
import sys, traceback def excepthook(*exc_info): print "cleanup - always run" raise Exception("error in cleanup") traceback.print_exception(*exc_info) sys.excepthook = excepthook raise Exception("error in main")
输出示例::
谢谢,对我来说这是一个全新的想法。是否有清除你提出的异常(“在__exit __期间发生异常”)的想法?如果是这样,你可以添加一个合适的'打印'清理 - 总是运行“'或类似的? – 2012-01-02 09:28:01
我已经按要求添加了打印语句。 – srgerg 2012-01-02 09:43:32
谢谢,srgerg。我正在阅读PEP。我认为我以前没有听说过或看过“with”关键字,但也许我只是没有注意。将一个清理代码放入输入或退出函数中,还是不会产生影响? – 2012-01-02 09:45:48