使用 assert 的最佳实践是什么?

600 投票
15 回答
304611 浏览
提问于 2025-04-15 12:01
  1. 使用 assert 作为标准代码的一部分,而不仅仅是用来调试,这样做会影响性能或者代码维护吗?

    这样写

    assert x >= 0, 'x is less than zero'
    

    比这样写

    if x < 0:
        raise Exception('x is less than zero')
    

    要好还是要差呢?

  2. 另外,有没有办法设置一个业务规则,比如 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

撰写回答