检查 Python 中的 __debug__ 和其他一些条件

问题描述 投票:0回答:2

在Python中有时我想做类似(1)的事情

if __debug__ and verbose: print "whatever"

如果 Python 使用 -O 运行,那么我希望整段代码消失,就像我只有 (2) 那样

if __debug__: print "whatever"

甚至 (3)

if __debug__:
    if verbose: print foo

然而,这似乎并没有发生(见下文)。有没有一种方法可以让我获得 #3 的运行时效率,同时使用更像 #1 的紧凑代码?

以下是我如何测试我没有获得我想要的高效代码:

#!/usr/bin/python2.7

from dis import dis
import sys

cmds = ["""
def func ():
    if __debug__ and 1+1: sys.stdout.write('spam')""",   """
def func():
    if __debug__: sys.stdout.write('ham')""",     """
def func():
    __debug__ and sys.stdout.write('eggs')"""]

print "__debug__ is", __debug__, "\n\n\n"

for cmd in cmds:
    print "*"*80, "\nSource of {}\n\ncompiles to:".format(cmd)
    exec(cmd)
    dis(func)
    print "\n"*4

运行这个给出

__debug__ is False 



******************************************************************************** 
Source of 
def func ():
    if __debug__ and 1+1: sys.stdout.write('spam')

compiles to:
  3           0 LOAD_GLOBAL              0 (__debug__)
              3 POP_JUMP_IF_FALSE       31
              6 LOAD_CONST               3 (2)
              9 POP_JUMP_IF_FALSE       31
             12 LOAD_GLOBAL              1 (sys)
             15 LOAD_ATTR                2 (stdout)
             18 LOAD_ATTR                3 (write)
             21 LOAD_CONST               2 ('spam')
             24 CALL_FUNCTION            1
             27 POP_TOP             
             28 JUMP_FORWARD             0 (to 31)
        >>   31 LOAD_CONST               0 (None)
             34 RETURN_VALUE        





******************************************************************************** 
Source of 
def func():
    if __debug__: sys.stdout.write('ham')

compiles to:
  3           0 LOAD_CONST               0 (None)
              3 RETURN_VALUE        





******************************************************************************** 
Source of 
def func():
    __debug__ and sys.stdout.write('eggs')

compiles to:
  3           0 LOAD_GLOBAL              0 (__debug__)
              3 JUMP_IF_FALSE_OR_POP    21
              6 LOAD_GLOBAL              1 (sys)
              9 LOAD_ATTR                2 (stdout)
             12 LOAD_ATTR                3 (write)
             15 LOAD_CONST               1 ('eggs')
             18 CALL_FUNCTION            1
        >>   21 POP_TOP             
             22 LOAD_CONST               0 (None)
             25 RETURN_VALUE        
python debugging compilation
2个回答
5
投票

不,你不能。 Python 的编译器还不够智能,无法检测在什么情况下可以删除代码块和

if
语句。

否则Python将不得不进行大量的逻辑推理。比较:

if __debug__ or verbose:

if __debug__ and verbose:

例如。 Python 必须在编译时检测这两个表达式之间的差异;一个可以优化掉,另一个则不能。

请注意,在其他条件相同的情况下,带有和不带有

if __debug__
语句的代码之间的运行时差异确实很小。一个小的常数值测试和跳跃并不是什么值得大惊小怪的,真的。


0
投票

您可以从 Python 3.10+ 开始执行此操作。只要你防止 if 条件变得太复杂并首先检查

__debug__
,较新的 python 版本就会按照你想要的方式运行。这是原始代码的修改版本:

from dis import dis
import sys

def func_debug_only(x):
    if __debug__:
        print('spam')

def func_debug_and_const(x):
    if __debug__ and True:
        print('spam')

def func_debug_and_var(x):
    if __debug__ and x: # -O deletes in this order
        print('spam')

def func_debug_and_var2(x):
    if x and __debug__: # -O doesn't delete in this order
        print('spam')

def func_debug_nested(x):
    if __debug__:
        if x:
            print('spam')

print("__debug__ is", __debug__, "on version", sys.version_info)
for fn in [func_debug_only, func_debug_and_const, func_debug_and_var, func_debug_and_var2, func_debug_nested]:
    print('\n', fn.__name__)
    dis(fn)

这给你:

__debug__ is False on version sys.version_info(major=3, minor=10, micro=5, releaselevel='final', serial=0)

 func_debug_only
  6           0 LOAD_CONST               0 (None)
              2 RETURN_VALUE

 func_debug_and_const
 11           0 LOAD_CONST               0 (None)
              2 RETURN_VALUE

 func_debug_and_var
 16           0 LOAD_CONST               0 (None)
              2 RETURN_VALUE

 func_debug_and_var2
 21           0 LOAD_FAST                0 (x)
              2 POP_JUMP_IF_FALSE        4 (to 8)
              4 LOAD_CONST               0 (None)
              6 RETURN_VALUE
        >>    8 LOAD_CONST               0 (None)
             10 RETURN_VALUE

 func_debug_nested
 26           0 LOAD_CONST               0 (None)
              2 RETURN_VALUE
© www.soinside.com 2019 - 2024. All rights reserved.