Python允许您通过传递-O选项以“优化模式”运行脚本。如果我将此脚本保存为“assert.py”:
assert False
print("Hello")
然后这两次Python调用会产生不同的输出(一个打印异常消息和堆栈跟踪,另一个打招呼):
python -m assert
python -O -m assert
Python脚本的作者可以通过检查全局名称__debug__
的值来确定Python是否处于优化模式。这允许我们根据我们是否以优化模式运行来执行不同的操作。
如果Python处于优化模式,假设我想做一件事,如果不是,那么我想做另一件事。这很容易 - 我们可以使用if __debug__:
。但现在假设我想要对每种情况下的行为进行单元测试是正确的。我应该怎么做呢?
我想到我可以设置__debug__
的值,但是你不允许这样做:
>>> __debug__ = False
File "<stdin>", line 1
SyntaxError: assignment to keyword
>>>
答案 0 :(得分:2)
考虑以下代码:
assert 123
if __debug__:
do_something()
优化的字节码将为空。在字节码编译期间评估assert
和裸if __debug__
语句,而不是在运行时。因此,即使您成功更改__debug__
(例如使用setattr(builtins, '__debug__', True)
),您仍然无法执行该代码。
唯一的方法是运行测试套件两次,首先是-O
,然后是-O
。显然,您可以自动执行此部件,您无需手动执行此操作。
为了完整性:
$ python3
>>> dis.dis('assert 123')
1 0 LOAD_CONST 0 (123)
3 POP_JUMP_IF_TRUE 12
6 LOAD_GLOBAL 0 (AssertionError)
9 RAISE_VARARGS 1
>> 12 LOAD_CONST 1 (None)
15 RETURN_VALUE
>>> dis.dis('if __debug__: do_something()')
1 0 LOAD_NAME 0 (do_something)
3 CALL_FUNCTION 0 (0 positional, 0 keyword pair)
6 POP_TOP
7 LOAD_CONST 0 (None)
10 RETURN_VALUE
$ python3 -O
>>> dis.dis('assert 123')
1 0 LOAD_CONST 0 (None)
3 RETURN_VALUE
>>> dis.dis('if __debug__: do_something()')
1 0 LOAD_CONST 0 (None)
3 RETURN_VALUE
请注意,只会优化裸if __debug__
个语句。如果使用复杂条件,它们将出现在字节码中:
$ python3 -O
>>> dis.dis('if __debug__ and something_else: do_something()')
1 0 LOAD_NAME 0 (__debug__)
3 POP_JUMP_IF_FALSE 22
6 LOAD_NAME 1 (something_else)
9 POP_JUMP_IF_FALSE 22
12 LOAD_NAME 2 (do_something)
15 CALL_FUNCTION 0 (0 positional, 0 keyword pair)
18 POP_TOP
19 JUMP_FORWARD 0 (to 22)
>> 22 LOAD_CONST 0 (None)
25 RETURN_VALUE