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?


当前回答

我补充说,我经常使用断言来指定属性,比如循环不变量或我的代码应该具有的逻辑属性,就像我在正式验证的软件中指定它们一样。

它们有两个目的,告诉读者,帮助我推理,并检查我在推理中没有犯错误。例如 :

k = 0
for i in range(n):
    assert k == i * (i + 1) // 2
    k += i 
    #do some things      

或者在更复杂的情况下:

def sorted(l):
   return all(l1 <= l2 for l1, l2 in zip(l, l[1:]))
 
def mergesort(l):
   if len(l) < 2: #python 3.10 will have match - case for this instead of checking length
      return l
   k = len(l // 2)
   l1 = mergesort(l[:k])
   l2 = mergesort(l[k:])
   assert sorted(l1) # here the asserts allow me to explicit what properties my code should have
   assert sorted(l2) # I expect them to be disabled in a production build
   return merge(l1, l2)

因为当python在优化模式下运行时,断言是禁用的,所以不要犹豫在它们中编写代价高昂的条件,特别是当它使您的代码更清晰,更不容易出现错误时

其他回答

"assert"语句在编译优化时被删除。所以,是的,它们在性能和功能上都有差异。

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

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

参见PYTHONOPTIMIZE和-O -OO

当x在整个函数中小于零时,能够自动抛出错误。您可以使用类描述符。这里有一个例子:

class LessThanZeroException(Exception):
    pass

class variable(object):
    def __init__(self, value=0):
        self.__x = value

    def __set__(self, obj, value):
        if value < 0:
            raise LessThanZeroException('x is less than zero')

        self.__x  = value

    def __get__(self, obj, objType):
        return self.__x

class MyClass(object):
    x = variable()

>>> m = MyClass()
>>> m.x = 10
>>> m.x -= 20
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "my.py", line 7, in __set__
    raise LessThanZeroException('x is less than zero')
LessThanZeroException: x is less than zero

除了其他答案之外,断言本身也会抛出异常,但仅抛出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 没有东西会被打印出来

这种方法唯一真正的错误是,很难使用断言语句产生非常描述性的异常。如果你正在寻找更简单的语法,记住你也可以这样做:

class XLessThanZeroException(Exception):
    pass

def CheckX(x):
    if x < 0:
        raise XLessThanZeroException()

def foo(x):
    CheckX(x)
    #do stuff here

另一个问题是,使用assert进行正常的条件检查会使使用-O标志禁用调试断言变得困难。