为何 assert 不被广泛使用?
我发现,Python中的assert语句是一个很好的方法,可以用来捕捉那些绝对不应该发生的情况。而且,当代码被认为是正确的时候,Python可以通过优化来去掉这些assert语句。
这看起来是一个在调试模式下运行Python应用程序的完美机制。但是,观察一些Python项目,比如django、twisted和zope,发现几乎没有使用assert
。那么,为什么会这样呢?
为什么在Python社区中,assert语句不常被使用?
5 个回答
我不是这些项目的作者,所以这只是我根据自己的经验猜测的。要想得到确切的答案,最好还是直接问问那些项目的开发者。
在调试自己应用的时候,使用断言(assert)是很不错的选择。不过,正如你提供的链接所说,当应用程序能够预测并从某种状态中恢复时,使用条件判断会更好。我没有用过zope,但在Twisted和Django这两个框架中,它们的应用能够从你代码中的许多错误中恢复并继续运行。从某种意义上说,它们已经“处理掉”了断言,因为它们实际上可以处理这些错误。
还有一个相关的原因是,很多使用外部库的应用程序,比如你列出的那些,可能需要进行错误处理。如果库只是使用断言,那么无论出现什么错误,它都会抛出一个AssertionError
。而使用条件判断的话,这些库就可以抛出一些有用的错误信息,这样你的应用就能捕捉到并处理这些错误。
有几个原因可以考虑……
这不是主要功能
很多程序员在思考这个问题时,往往会忽视那些与程序主要功能没有直接关系的东西。assert语句主要是用来调试和测试的,所以在他们看来,这是一种奢侈品,根本没时间去关注。
单元测试
assert语句的出现比单元测试要早。虽然assert语句在某些情况下还是有用的,但现在单元测试已经成为一种常见的方法,用来创建一个严苛的环境,来彻底测试一个子程序及其系统。在这种情况下,assert语句就像是在枪战中用刀子,显得不太合适。
行业对测试的重视提高
assert语句最有效的作用是作为最后的防线。它在C语言盛行的时候达到了一个很高的地位,那时它被视为实现“防御性编程”的好方法;它能够在灾难发生的边缘及时识别并捕捉问题。这是在测试的价值被广泛认可之前,那时灾难发生得更频繁。
如今,任何严肃的商业软件发布时几乎都不会没有经过某种形式的测试。测试变得非常重要,已经发展成一个庞大的领域。现在有专门的测试人员和质量保证部门,他们有详细的检查清单和正式的签字流程。在这种情况下,程序员通常不会太在意assert,因为他们相信自己的代码会经过大量繁琐的测试,这样出现问题的可能性几乎可以忽略不计。这并不是说他们一定是对的,但如果可以把懒惰编程的责任推给质量保证部门,那为什么不呢?
我想主要原因是大家不太使用Python的“优化”模式,所以assert
这个功能没有被更广泛地使用。
assert是一个很好的工具,可以帮助我们发现编程中的错误,保护自己免受意外情况的影响。不过,这种错误检查是有代价的。在像C/C++这样的编译语言中,这个代价并不大,因为assert只在调试版本中启用,而在发布版本中完全去掉。
而在Python中,调试模式和发布模式之间并没有严格的区分。解释器有一个“优化标志”(-O
),但目前这个标志并不会真正优化字节码,只是去掉assert。
因此,大多数Python用户都忽略了-O
这个标志,直接在“正常模式”下运行他们的脚本,这种模式算是调试模式,因为assert是启用的,__debug__
的值是True
,但也被认为是“可以投入生产”的。
也许更明智的做法是反过来,默认“优化”,只有在明确的调试模式下才启用assert(*),但我想这会让很多用户感到困惑,我怀疑我们会看到这样的改变。
((*) 比如Java虚拟机就是这样做的,有一个-ea
(启用assert)选项。)