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"语句在编译优化时被删除。所以,是的,它们在性能和功能上都有差异。

在编译时请求优化时,当前代码生成器不会为assert语句生成代码。Python 3 Docs

如果您使用assert来实现应用程序功能,然后优化部署到生产环境,那么您将受到“但它在开发中有效”缺陷的困扰。

参见PYTHONOPTIMIZE和-O -OO

其他回答

无论如何,如果你处理的代码依赖assert来正常工作,那么添加以下代码将确保assert被启用:

try:
    assert False
    raise Exception('Python assertions are not working. This tool relies on Python assertions to do its job. Possible causes are running with the "-O" flag or running a precompiled (".pyo" or ".pyc") module.')
except AssertionError:
    pass

是否存在性能问题?

Please remember to "make it work first before you make it work fast". Very few percent of any program are usually relevant for its speed. You can always kick out or simplify an assert if it ever proves to be a performance problem -- and most of them never will. Be pragmatic: Assume you have a method that processes a non-empty list of tuples and the program logic will break if those tuples are not immutable. You should write: def mymethod(listOfTuples): assert(all(type(tp)==tuple for tp in listOfTuples)) This is probably fine if your lists tend to be ten entries long, but it can become a problem if they have a million entries. But rather than discarding this valuable check entirely you could simply downgrade it to def mymethod(listOfTuples): assert(type(listOfTuples[0])==tuple) # in fact _all_ must be tuples! which is cheap but will likely catch most of the actual program errors anyway.

断言应该用于测试不应该发生的情况。目的是在程序状态损坏的情况下尽早崩溃。

异常应该用于可能发生的错误,并且几乎总是应该创建自己的Exception类。


例如,如果您正在编写一个从配置文件读取到dict的函数,那么文件中的不当格式将引发ConfigurationSyntaxError,而您可以断言您不会返回None。


在您的示例中,如果x是通过用户界面或外部源设置的值,则最好使用异常。

如果x只是在同一个程序中由您自己的代码设置的,则使用断言。

在诸如PTVS、PyCharm、Wing assert isinstance()等IDE中,可以使用isinstance语句对一些不清楚的对象启用代码补全。

如前所述,当您的代码should NOT到达某个点(意味着那里存在错误)时,应该使用断言。在我看来,使用断言最有用的原因可能是不变量/前置/后置条件。在循环或函数的每次迭代的开始或结束时,这些必须为真。

例如,一个递归函数(两个独立的函数,一个处理错误的输入,另一个处理错误的代码,因为它很难与递归区分开来)。如果我忘记写if语句,这将很明显地显示出哪里出了问题。

def SumToN(n):
    if n <= 0:
        raise ValueError, "N must be greater than or equal to 0"
    else:
        return RecursiveSum(n)

def RecursiveSum(n):
    #precondition: n >= 0
    assert(n >= 0)
    if n == 0:
        return 0
    return RecursiveSum(n - 1) + n
    #postcondition: returned sum of 1 to n

这些循环不变量通常可以用断言表示。