Is there a performance or code maintenance issue with using assert as part of the standard code instead of using it just for debugging purposes? Is assert x >= 0, 'x is less than zero' better or worse than if x < 0: raise Exception('x is less than zero') Also, is there any way to set a business rule like if x < 0 raise error that is always checked without the try/except/finally so, if at anytime throughout the code x is less than 0 an error is raised, like if you set assert x < 0 at the start of a function, anywhere within the function where x becomes less then 0 an exception is raised?
当前回答
assert的四个目的
假设您与四位同事Alice、Bernd、Carl和Daphne一起处理20万行代码。 他们喊你的代码,你喊他们的代码。
那么assert有四个角色:
Inform Alice, Bernd, Carl, and Daphne what your code expects. Assume you have a method that processes a list of tuples and the program logic can break if those tuples are not immutable: def mymethod(listOfTuples): assert(all(type(tp)==tuple for tp in listOfTuples)) This is more trustworthy than equivalent information in the documentation and much easier to maintain. Inform the computer what your code expects. assert enforces proper behavior from the callers of your code. If your code calls Alices's and Bernd's code calls yours, then without the assert, if the program crashes in Alices code, Bernd might assume it was Alice's fault, Alice investigates and might assume it was your fault, you investigate and tell Bernd it was in fact his. Lots of work lost. With asserts, whoever gets a call wrong, they will quickly be able to see it was their fault, not yours. Alice, Bernd, and you all benefit. Saves immense amounts of time. Inform the readers of your code (including yourself) what your code has achieved at some point. Assume you have a list of entries and each of them can be clean (which is good) or it can be smorsh, trale, gullup, or twinkled (which are all not acceptable). If it's smorsh it must be unsmorshed; if it's trale it must be baludoed; if it's gullup it must be trotted (and then possibly paced, too); if it's twinkled it must be twinkled again except on Thursdays. You get the idea: It's complicated stuff. But the end result is (or ought to be) that all entries are clean. The Right Thing(TM) to do is to summarize the effect of your cleaning loop as assert(all(entry.isClean() for entry in mylist)) This statements saves a headache for everybody trying to understand what exactly it is that the wonderful loop is achieving. And the most frequent of these people will likely be yourself. Inform the computer what your code has achieved at some point. Should you ever forget to pace an entry needing it after trotting, the assert will save your day and avoid that your code breaks dear Daphne's much later.
在我看来,assert的两个文档目的(1和3)和 保障措施(2和4)同样有价值。 告知人民甚至可能比告知计算机更有价值 因为它可以防止assert要捕捉的错误(在情况1中) 无论如何,接下来还有很多错误。
其他回答
assert的使用和异常的引发都与通信有关。
Assertions are statements about the correctness of code addressed at developers: An assertion in the code informs readers of the code about conditions that have to be fulfilled for the code being correct. An assertion that fails at run-time informs developers that there is a defect in the code that needs fixing. Exceptions are indications about non-typical situations that can occur at run-time but can not be resolved by the code at hand, addressed at the calling code to be handled there. The occurence of an exception does not indicate that there is a bug in the code.
最佳实践
因此,如果您将运行时发生的特定情况视为您想要通知开发人员的错误(“嗨,开发人员,这种情况表明某处存在错误,请修复代码。”),那么请使用断言。如果断言检查代码的输入参数,当输入参数违反条件时,您通常应该在文档中添加代码具有“未定义行为”。
相反,如果这种情况的出现并不是您眼中的错误,而是您认为应该由客户端代码处理的(可能很少,但可能)情况,则引发异常。引发哪种异常的情况应该是相应代码文档的一部分。
有没有演出[…]使用assert时的问题
断言的计算需要一些时间。但是,它们可以在编译时被删除。然而,这有一些后果,见下文。
有[…]使用assert的代码维护问题
Normally assertions improve the maintainability of the code, since they improve readability by making assumptions explicit and during run-time regularly verifying these assumptions. This will also help catching regressions. There is one issue, however, that needs to be kept in mind: Expressions used in assertions should have no side-effects. As mentioned above, assertions can be eliminated at compile time - which means that also the potential side-effects would disappear. This can - unintendedly - change the behaviour of the code.
除了其他答案之外,断言本身也会抛出异常,但仅抛出AssertionErrors。从实用主义的角度来看,当您需要对捕获的异常进行精细控制时,断言并不适合。
Assert是检查- 1. 有效条件, 2. 有效的表述, 3.真正的逻辑; 源代码。它不会让整个项目失败,而是会发出警报,提示源文件中有些地方不合适。
在例1中,因为变量'str'不是空的。因此不会引发任何断言或异常。
示例1:
#!/usr/bin/python
str = 'hello Python!'
strNull = 'string is Null'
if __debug__:
if not str: raise AssertionError(strNull)
print str
if __debug__:
print 'FileName '.ljust(30,'.'),(__name__)
print 'FilePath '.ljust(30,'.'),(__file__)
------------------------------------------------------
Output:
hello Python!
FileName ..................... hello
FilePath ..................... C:/Python\hello.py
在例2中,var 'str'为空。因此,我们可以通过assert语句来避免用户走在错误程序前面。
示例2:
#!/usr/bin/python
str = ''
strNull = 'NULL String'
if __debug__:
if not str: raise AssertionError(strNull)
print str
if __debug__:
print 'FileName '.ljust(30,'.'),(__name__)
print 'FilePath '.ljust(30,'.'),(__file__)
------------------------------------------------------
Output:
AssertionError: NULL String
当我们不想调试并意识到源代码中的断言问题时。禁用优化标志
python -O assertStatement.py 没有东西会被打印出来
断言应该用于测试不应该发生的情况。目的是在程序状态损坏的情况下尽早崩溃。
异常应该用于可能发生的错误,并且几乎总是应该创建自己的Exception类。
例如,如果您正在编写一个从配置文件读取到dict的函数,那么文件中的不当格式将引发ConfigurationSyntaxError,而您可以断言您不会返回None。
在您的示例中,如果x是通过用户界面或外部源设置的值,则最好使用异常。
如果x只是在同一个程序中由您自己的代码设置的,则使用断言。
这种方法唯一真正的错误是,很难使用断言语句产生非常描述性的异常。如果你正在寻找更简单的语法,记住你也可以这样做:
class XLessThanZeroException(Exception):
pass
def CheckX(x):
if x < 0:
raise XLessThanZeroException()
def foo(x):
CheckX(x)
#do stuff here
另一个问题是,使用assert进行正常的条件检查会使使用-O标志禁用调试断言变得困难。