使用 assert 的最佳实践是什么?
使用
assert
作为标准代码的一部分,而不仅仅是用来调试,这样做会影响性能或者代码维护吗?这样写
assert x >= 0, 'x is less than zero'
比这样写
if x < 0: raise Exception('x is less than zero')
要好还是要差呢?
另外,有没有办法设置一个业务规则,比如
if x < 0 raise error
,让它始终被检查,而不使用try/except/finally
?也就是说,如果在代码的任何地方x
小于 0,就会抛出一个错误。就像在一个函数开始时设置assert x < 0
,那么在函数内部的任何地方,只要x
变成小于 0,就会抛出异常?
15 个回答
459
“assert”语句在编译优化时会被移除。所以,确实存在性能和功能上的差异。
当前的代码生成器在编译时请求优化时,不会为assert语句生成任何代码。 - Python 2 文档 Python 3 文档
如果你用 assert
来实现应用程序的功能,然后在部署到生产环境时进行优化,你可能会遇到“但在开发环境中可以运行”的问题。
请查看 PYTHONOPTIMIZE 和 -O -OO
870
断言应该用来测试那些绝对不应该发生的情况。这样做的目的是在程序状态出现问题时,尽早崩溃,方便我们发现问题。
而异常则是用来处理那些可能会发生的错误,你几乎总是应该自己创建异常类。
举个例子,如果你在写一个函数,用来从配置文件读取数据到一个dict
(字典)里,如果文件格式不正确,就应该抛出一个ConfigurationSyntaxError
(配置语法错误),而你可以用assert
来确保你不会返回None
。
在你的例子中,如果x
是通过用户界面或外部来源设置的值,使用异常是最合适的。
如果x
只是由你自己在同一个程序中设置的,那就用断言。
165
为了在函数中自动抛出错误,当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