我发现,Python 的断言语句是一个很好的方法来捕捉情况,永远不应该发生。当代码被信任为正确时,可以通过 Python 优化删除它。
它似乎是在调试模式下运行 Python 应用程序的完美机制。但是看看几个 Python 项目,比如 django、 Twist 和 zope,几乎从来没有使用过 assert。为什么会这样?
assert
为什么在 Python 社区中不经常使用断言语句?
我不是这些项目的作者,所以这只是基于我个人经验的猜测。如果不直接询问这些项目中的人,你将得不到一个具体的答案。
当您试图在自己的应用程序中执行调试等操作时,断言非常有用。但是,正如您提供的链接中所述,当应用程序可能能够预测状态并从状态恢复时,使用条件更好。我没有使用 zope,但是在 Twsted 和 Django 中,它们的应用程序都能够从代码中的许多错误中恢复和继续。在某种意义上,他们已经“编译”了断言,因为他们实际上可以处理它们。
与此相关的另一个原因是,通常使用外部库(如您列出的那些库)的应用程序可能希望执行错误处理。如果库只是使用断言,那么无论出现什么错误,它都会引发 AssertionError。使用条件,库实际上可以抛出有用的错误,应用程序可以捕获和处理这些错误。
AssertionError
我想 assert没有被更多地使用的主要原因是 没有人使用 Python 的“优化”模式。
断言是检测编程错误、防止意外情况发生的一个很好的工具,但是所有这些错误检查都是有代价的。在诸如 C/C + + 这样的编译语言中,这并不重要,因为只有在调试构建中才启用断言,并且从发布构建中完全删除断言。
另一方面,在 Python 中,调试和 释放模式之间没有严格的区别。解释器具有一个“优化标志”(-O) ,但是目前这并不实际优化字节码,而只是删除断言。
-O
因此,大多数 Python 用户只是忽略 -O标志,以“正常模式”运行他们的脚本,这是 算是吧调试模式,因为断言是启用的,而 __debug__是 True,但被认为是“生产就绪”。
__debug__
True
也许更明智的做法是切换逻辑,比如,默认情况下“优化”,只在显式调试模式(*)下启用断言,但我猜这会让很多用户感到困惑,我怀疑我们是否会看到这样的变化。
((*)这就是 JavaVM 如何做到这一点的例子,具有 -ea(启用断言)开关。)
-ea
我想到了几个原因。
它不是主要功能
许多程序员,让我们不要被这个基本原理所困扰,不尊重任何不是程序倒数第二个功能的直接参与者的东西。断言语句用于调试和测试,因此是他们无法承受的奢侈品。
单位测试
断言的出现早于单元测试的兴起。虽然断言语句仍然有其用途,但是单元测试现在被广泛用于构建一个恶意的环境,用来猛击一个子程序及其系统。在这种情况下,断言开始感觉像枪战中的利刃。
提高了行业对测试的尊重
断言语句最适合作为最后一道防线。当 C 语言统治世界的时候,作为一种实现新奇“防御性编程”的伟大方式,它在 C 语言的统治下达到了崇高而不可触及的高度,在灾难摇摇欲坠的时候,它能够识别并捕捉到灾难性的灾难。这是在测试的价值得到广泛认可和尊重,灾难更加普遍之前。
今天,任何严肃的商业软件在没有任何形式的测试的情况下发布都是闻所未闻的。测试被认真对待,已经发展成为一个庞大的领域。有测试专业人员和质量保证部门的大清单和正式签署。在这些情况下,程序员往往不会为断言而烦恼,因为他们相信自己的代码将经受如此多令人厌烦的测试,以至于古怪的灾难边缘条件发生的几率是如此之小,以至于可以忽略不计。这并不是说他们是对的,但是如果懒惰编程的责任可以转移到 QA 部门,为什么不呢?
根据我的经验,assert主要用于程序的开发阶段-检查用户定义的输入。实际上并不需要 assert来捕获编程错误。Python 本身能够很好地捕获真正的编程错误,比如 ZeroDivisionError, TypeError左右。
ZeroDivisionError, TypeError