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?
当前回答
断言应该用于测试不应该发生的情况。目的是在程序状态损坏的情况下尽早崩溃。
异常应该用于可能发生的错误,并且几乎总是应该创建自己的Exception类。
例如,如果您正在编写一个从配置文件读取到dict的函数,那么文件中的不当格式将引发ConfigurationSyntaxError,而您可以断言您不会返回None。
在您的示例中,如果x是通过用户界面或外部源设置的值,则最好使用异常。
如果x只是在同一个程序中由您自己的代码设置的,则使用断言。
其他回答
我补充说,我经常使用断言来指定属性,比如循环不变量或我的代码应该具有的逻辑属性,就像我在正式验证的软件中指定它们一样。
它们有两个目的,告诉读者,帮助我推理,并检查我在推理中没有犯错误。例如 :
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被启用:
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
如前所述,当您的代码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
这些循环不变量通常可以用断言表示。
当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
这种方法唯一真正的错误是,很难使用断言语句产生非常描述性的异常。如果你正在寻找更简单的语法,记住你也可以这样做:
class XLessThanZeroException(Exception):
pass
def CheckX(x):
if x < 0:
raise XLessThanZeroException()
def foo(x):
CheckX(x)
#do stuff here
另一个问题是,使用assert进行正常的条件检查会使使用-O标志禁用调试断言变得困难。
推荐文章
- 有没有办法在python中做HTTP PUT
- “foo Is None”和“foo == None”之间有什么区别吗?
- 类没有对象成员
- Django模型“没有显式声明app_label”
- 熊猫能自动从CSV文件中读取日期吗?
- 在python中zip的逆函数是什么?
- 有效的方法应用多个过滤器的熊猫数据框架或系列
- 如何检索插入id后插入行在SQLite使用Python?
- 我如何在Django中添加一个CharField占位符?
- 如何在Python中获取当前执行文件的路径?
- 我如何得到“id”后插入到MySQL数据库与Python?
- super()失败,错误:TypeError "参数1必须是类型,而不是classobj"当父不继承对象
- Python内存泄漏
- 实现嵌套字典的最佳方法是什么?
- 如何在tensorflow中获得当前可用的gpu ?