处理“异常情况”是编程中最具争议的问题之一。这可能是因为风险很高:处理不当的错误值甚至可能导致最大的系统崩溃。由于“异常情况”本质上是最少被测试的,但发生频率却令人不快,因此正确处理它们通常可以将一个充满恐怖故事的系统与一个“正常工作”的系统区分开来。
从 Java 的 checked 异常到 Erlang 的故障隔离,再到 Haskell 的 Maybe,不同的语言对错误处理的态度截然不同。
《Zen》提供了 Python 对这个主题的思考。
错误绝不应该悄无声息地发生……
在 Python 之禅在 Tim Peters 的眼中闪烁之前,在 Wikipedia 非正式地被称为“wiki”之前,第一个 WikiWiki 网站 C2 就已经存在,作为一个编程指南的宝库。这些原则主要来自 Smalltalk 编程社区。Smalltalk 的思想影响了许多面向对象的语言,包括 Python。
C2 wiki 定义了武士原则:“要么凯旋而归,要么一无所获。” 在 Pythonic 术语中,它鼓励避免使用哨兵值,例如返回 None 或 -1 来表示无法完成任务,而是倾向于引发异常。 None 是沉默的:它看起来像一个值,可以放在变量中并传递。有时,它甚至是一个有效的返回值。
这里的原则是,如果一个函数无法完成其契约,它应该“大声失败”:引发异常。引发的异常永远不会看起来像一个可能的值。它将跳过 returned_value = call_to_function(parameter) 行并向上堆栈,可能导致程序崩溃。
崩溃很容易调试:有一个堆栈跟踪指示问题以及调用堆栈。失败可能意味着程序的一个必要条件未满足,需要人工干预。这可能意味着程序的逻辑有缺陷。在任何一种情况下,大声失败都比隐藏的“缺失”值要好,后者会用 None 感染程序的有效数据,直到在某处使用它并且错误消息显示“None 没有方法 split”,这您可能已经知道了。
除非明确地被静音。
有时需要显式捕获异常。我们可能会预料到文件中某些行的格式不正确,并希望以特殊方式处理这些行,也许通过将它们放在“供人查看的行”文件中,而不是使整个程序崩溃。
Python 允许我们使用 except 捕获异常。这意味着错误可以被明确地静音。这种明确性意味着 except 行在代码审查中是可见的。有理由质疑为什么这是静音并可能从异常中恢复的正确位置。有理由询问我们是否捕获了太多或太少的异常。
因为这一切都是明确的,所以有人可以阅读代码并理解哪些异常情况是可以恢复的。
评论已关闭。