【发布时间】:2010-11-19 09:09:44
【问题描述】:
如何在 Python 中禁用断言?
也就是说,如果一个断言失败,我不希望它抛出一个AssertionError,而是继续下去。
我该怎么做?
【问题讨论】:
标签: python debugging exception-handling environment-variables assert
如何在 Python 中禁用断言?
也就是说,如果一个断言失败,我不希望它抛出一个AssertionError,而是继续下去。
我该怎么做?
【问题讨论】:
标签: python debugging exception-handling environment-variables assert
在优化模式下运行应该可以做到:
python -OO module.py
【讨论】:
使用python -O:
$ python -O
>>> assert False
>>>
【讨论】:
使用 -O 标志调用 Python:
test.py:
assert False
print('Done')
输出:
C:\temp\py>C:\Python26\python.exe test.py
Traceback (most recent call last):
File "test.py", line 1, in <module>
assert(False)
AssertionError
C:\temp\py>C:\Python26\python.exe -O test.py
Done
【讨论】:
已经给出的两个答案都是有效的(在命令行上使用-O 或-OO 调用Python)。
来自Python documentation,这里是他们之间的区别:
-O开启基本优化。这会更改文件扩展名
用于从 .pyc 到 .pyo 的编译(字节码)文件。
-OO 在-O 优化之外丢弃文档字符串。
要检查断言是启用还是禁用,请查看__debug__ 的值。
【讨论】:
您应该不禁用断言。当注意力转移到别处时,他们会发现意料之外的错误。请参阅"The power of ten"(DOI、Wikipedia)中的规则 5。
编写raise 语句,而不是assert 语句:
if x_is_broken():
raise RuntimeError('`x` is broken.')
无论运行 Python 的优化选项如何,raise 语句仍然存在。此外,使用raise 语句可以指定不同于AssertionError 的异常类型。这对用户非常有用。此外,仅仅写一个raise 语句就会提示自己问自己AssertionError 是否是正确的选择。
此外,在编写raise 语句时,我们被引导编写一条信息性消息,例如raise AssertionError('An error occurred with `x`.')。在assert 语句中写入错误消息是可能的(例如,assert x, 'An error occurred with `x`.',括号可用于写入多行的消息),但是,它可能会被忘记。相比之下,raise AssertionError(....) 要求填写 ....(而raise AssertionError 的形式不常见,不推荐使用)。
在编写错误消息时,会发现多少进一步的编码错误。
旁注:计算量大的断言检查只能在请求时运行。一种方法是:
import logging
log = logging.getLogger(__name__)
if log.getEffectiveLevel() < logging.DEBUG:
if not check_expensive_property(x):
raise RuntimeError('`x` is broken.')
【讨论】:
如何在 Python 中禁用断言?
有多种方法会影响单个进程、环境或单行代码。
我分别演示。
使用-O 标志(大写O)禁用进程中的所有断言语句。
例如:
$ python -Oc "assert False"
$ python -c "assert False"
Traceback (most recent call last):
File "<string>", line 1, in <module>
AssertionError
请注意,禁用我的意思是它也不执行它后面的表达式:
$ python -Oc "assert 1/0"
$ python -c "assert 1/0"
Traceback (most recent call last):
File "<string>", line 1, in <module>
ZeroDivisionError: integer division or modulo by zero
您也可以使用环境变量来设置此标志。
这将影响使用或继承环境的每个进程。
例如,在 Windows 中,设置然后清除环境变量:
C:\>python -c "assert False"
Traceback (most recent call last):
File "<string>", line 1, in <module>
AssertionError
C:\>SET PYTHONOPTIMIZE=TRUE
C:\>python -c "assert False"
C:\>SET PYTHONOPTIMIZE=
C:\>python -c "assert False"
Traceback (most recent call last):
File "<string>", line 1, in <module>
AssertionError
在 Unix 中相同(使用 set 和 unset 来实现各自的功能)
你继续你的问题:
如果一个断言失败,我不希望它抛出一个 AssertionError,而是继续。
如果您希望执行失败的代码,您可以捕获确保控制流未到达断言,例如:
if False:
assert False, "we know this fails, but we don't get here"
或者你可以捕获断言错误:
try:
assert False, "this code runs, fails, and the exception is caught"
except AssertionError as e:
print(repr(e))
哪个打印:
AssertionError('this code runs, fails, and the exception is caught')
您将从处理AssertionError 的那一刻开始继续前进。
这样的断言语句:
assert expression #, optional_message
相当于
if __debug__: if not expression: raise AssertionError #(optional_message)
还有,
内置变量
__debug__正常情况下为True,请求优化时为False(命令行选项-O)。
还有更多
分配给
__debug__是非法的。内置变量的值在解释器启动时确定。
来自使用文档:
开启基本优化。这会将已编译(字节码)文件的文件扩展名从 .pyc 更改为 .pyo。另请参阅 PYTHONOPTIMIZE。
和
如果设置为非空字符串,则等效 指定
-O选项。如果设置为整数,则相当于 多次指定-O。
【讨论】:
__debug__ 设置为 False,但这是不允许的。
if False: assert False),或者您可以捕获断言错误。这些是你的选择。更新了答案以解决您的问题。
foo() 并关闭断言:with skip_assertion(): foo()。这样做的好处是我不必在函数上添加另一个标志
Pass 对象替换 Assert 对象)。上下文管理器不会直接为此工作,但您可以拥有某种以这种方式使用修饰函数的机制。无论如何,我不推荐它。我怀疑您想要这样做的原因是您正在调用您无法控制的代码并获得 AssertionErrors。如果是这样,您可能需要找到不同的修复方法。