python断言用-O激发

时间:2014-03-24 20:15:11

标签: python assert

我正在尝试确保在使用-O时python不执行断言。然而,我的测试程序表明它总是被执行。我在命令行上专门使用-O,当我使用build和install运行setup.py时,我使用了-O。在我提交错误报告之前,我想确保我没有做任何新手错误......

所以我需要做一些别的或不同的事情,以便断言执行?

我的简单脚本:

print __debug__

if __debug__:
    print "True branch"
else:
    print "False branch"

assert(False)

独立运行时有效。打印:

False
False branch

当我在主程序中复制这个片段时(我不能包括在这里......)我得到:

False
True branch
AssertionError

我完全不知道如何发生这种情况。这是Mac上的Python 2.7.6。 (抱歉Mac,我必须用它来工作。)

1 个答案:

答案 0 :(得分:3)

您可以使用.pyc标志直接运行-O文件来实现您描述的效果。这是滥用事情的方式。你想要:

  1. 使用或不使用.py标记(通常的方法)运行-O文件,或
  2. 运行.pyc文件,不用 -O标志,或
  3. 使用 .pyo标志运行-O文件
  4. 如果您运行带有.pyc标记的-O文件或没有它的.pyo文件,您将会收到类似这样的惊喜。

    正在发生的事情是,在编译时,窥孔优化器已经优化了if __debug__分支,因此.pyc.pyo文件将无条件地执行相应的分支。然后,当您使用错误的-O规范运行时,您将运行的值__debug__与编译时应用的优化不匹配。

    前一段时间内,Python问题跟踪器上报告了similar issue,但情况恰恰相反:有人在不使用.pyo标志的情况下运行-O文件。

    一个简单的例子:假设我的文件有点像你的名字“debug_example.py”,它位于我当前的目录中:

    noether:Desktop mdickinson$ cat debug_example.py
    def main():
        print "__debug__ is {}".format(__debug__)
        if __debug__:
            print "__debug__ is True"
        else:
            print "__debug__ is False"
    
    if __name__ == '__main__':
        main()
    

    如果我们直接执行文件,无论是否带有-O标志,我们都会看到预期结果:

    noether:Desktop mdickinson$ python2 debug_example.py
    __debug__ is True
    __debug__ is True
    noether:Desktop mdickinson$ python2 -O debug_example.py
    __debug__ is False
    __debug__ is False
    

    现在让我们使用方便的py_compile模块将此文件编译为“debug_example.pyc”文件。 (在您的情况下,此编译可能是setup.py安装的一部分。):

    noether:Desktop mdickinson$ python2 -m py_compile debug_example.py
    noether:Desktop mdickinson$ ls -l debug_example.pyc
    -rw-r--r--  1 mdickinson  staff  350 24 Mar 21:41 debug_example.pyc
    

    现在我们执行debug_example.pyc文件,但是(错误地)使用-O标志,Python变得混乱:

    noether:Desktop mdickinson$ python2 -O debug_example.pyc
    __debug__ is False
    __debug__ is True
    

    我们可以使用Python's dis module查看模块中的字节码:

    Python 2.7.6 (default, Nov 18 2013, 15:12:51) 
    [GCC 4.2.1 Compatible Apple LLVM 5.0 (clang-500.2.79)] on darwin
    Type "help", "copyright", "credits" or "license" for more information.
    >>> import debug_example
    >>> import dis
    >>> dis.dis(debug_example)
    Disassembly of main:
      2           0 LOAD_CONST               1 ('__debug__ is {}')
                  3 LOAD_ATTR                0 (format)
                  6 LOAD_GLOBAL              1 (__debug__)
                  9 CALL_FUNCTION            1
                 12 PRINT_ITEM          
                 13 PRINT_NEWLINE       
    
      4          14 LOAD_CONST               2 ('__debug__ is True')
                 17 PRINT_ITEM          
                 18 PRINT_NEWLINE       
                 19 LOAD_CONST               0 (None)
                 22 RETURN_VALUE        
    

    请注意,根本没有与if语句对应的字节码:我们看到'__debug__ is True'的无条件打印。

    解决方案:不要直接执行.pyc.pyo文件:执行.py文件,让Python确定是否使用.pyc或{{ 1}}视情况而定。