在Python中禁用断言


Answers:


73

如何在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文档

如下的断言语句:

assert expression #, optional_message

相当于

if __debug__:
    if not expression: raise AssertionError #(optional_message)

和,

内置变量__debug__True在正常情况下,False当优化要求(命令行选项-O)。

并进一步

转让给__debug__是非法的。内置变量的值在解释器启动时确定。

从用法文档中:

-O

打开基本优化。这会将已编译(字节码)文件的文件扩展名从.pyc更改为.pyo。另请参阅PYTHONOPTIMIZE。

PYTHONOPTIMIZE

如果将其设置为非空字符串,则等效于指定-O选项。如果设置为整数,则等效于-O多次指定。


如果出现“代码中的单点”,是否可以跳过失败的代码?我尝试将其设置__debug__为False,但这是不允许的。
Matthijs,

1
@Matthijs您可以确保控制流没有到达它(例如if False: assert False),也可以捕获断言错误。这些是您的选择。更新了答案以解决您的问题。
亚伦·霍尔

感谢您的回答,但还不完全是我在想什么。我想在运行时禁用函数内的断言,理想情况下使用某种上下文管理器:评估断言:foo()并关闭断言:with skip_assertion(): foo()。这样做的好处是我不必在函数上添加其他标志
Matthijs

2
您可以重写函数的字节码,重写AST或重写函数本身。(无论是手动还是编程方式)。重写AST可能是最可靠的方法(“简单地”用Assert对象替换Pass对象)。上下文管理器不会直接为此工作,但是您可以拥有某种以这种方式使用修饰功能的机制。无论如何,我不建议这样做。我怀疑您想要这样做的原因是您正在调用不受控制的代码并获得AssertionErrors。如果是这样,您可能需要找到其他修复程序。
亚伦·霍尔

59

使用-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

8
断言不是函数,因此括号是多余的。
亚伦·霍尔

15

已经给出的两个答案都有效(使用-O-OO在命令行上调用Python )。

这是它们之间的区别:

  • -O打开基本优化。这会将已编译(字节码)文件的文件扩展名从.pyc更改为.pyo。

  • -OO放弃文档字符串除了-O优化。

(来自Python文档



3

你应该禁止(大多数)的断言。当注意力转移到其他地方时,它们会捕获意外错误。请参阅“十的力量”中的规则5 。

相反,可以通过以下方式保护一些昂贵的断言检查:

import logging
logger = logging.getLogger(__name__)

if logger.getEffectiveLevel() < logging.DEBUG:
    ok = check_expensive_property()
    assert ok, 'Run !'

保留重要断言并允许assert优化语句的一种方法是在选择语句中引发它们:

if foo_is_broken():
    raise AssertionError('Foo is broken!')

1
//,但问题是,该语句仍然增加了循环复杂性,而错误处理应该处理其余的吗?
内森·巴桑内斯

1
上面将要保护的断言是昂贵的调用,它们会大大降低执行速度。对于某些算法,这种检查可能比整个程序花费几个数量级。考虑运行相同算法的天真但更简单的实现(因此不太可能包含错误)来检查正确性。或者通过详尽枚举检查正常操作中无法解决的问题。
Ioannis Filippidis

我认为可读性没有太大问题,因为这样的语句不会在代码中添加嵌套。如果这是一个问题,则将其提取为函数调用可以将其移开(并且我希望这样的重构可以降低循环复杂性)。在任何情况下,圈复杂性都不应支配安全检查。
Ioannis Filippidis

2

以优化模式运行应该做到这一点:

python -OO module.py
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.