尽管__debug__为真,条件__debug__语句没有执行

13 投票
1 回答
14283 浏览
提问于 2025-04-17 18:28

简短版本

我正在调试一段代码,这段代码会检查一个叫 __debug__ 的值,如果它是 True,就会执行一些代码。

if __debug__:
  <stuff happens>

问题是,尽管 __debug__ 看起来是 True,但“事情”就是没有发生。

详细版本 / 细节

为了检查这个,我在函数执行时把几个变量的值打印到一个文件里,特别是 __debug__。我使用了以下的方式来实现这个。 (我用 os.open 是因为在这个模块里 open 已经被定义了。)

try:
  myfile = os.open("test.txt", os.O_RDWR|os.O_CREAT|os.O_APPEND)
  # work + some print statements to check the value of __DEBUG__
finally:
  os.close(myfile)

让我最困惑的那段代码看起来是这样的:

os.write(myfile, "LINE %s | LDAP FUNCTION __DEBUG__: %s \n" %(sys._getframe(0).f_lineno, __debug__))
os.write(myfile, "LINE %s | LDAP FUNCTION __DEBUG__: %s \n" %(sys._getframe(0).f_lineno, type(__debug__)))
os.write(myfile, "LINE %s | LDAP FUNCTION __DEBUG__: %s \n" %(sys._getframe(0).f_lineno, bool(__debug__)))
if __debug__:
  os.write(myfile, "LINE %s | LDAP FUNCTION __DEBUG__: %s \n" %(sys._getframe(0).f_lineno, __debug__))
if bool(__debug__):
  os.write(myfile, "LINE %s | LDAP FUNCTION __DEBUG__: %s \n" %(sys._getframe(0).f_lineno, __debug__))
if True:
  os.write(myfile, "LINE %s | LDAP FUNCTION __DEBUG__: %s \n" %(sys._getframe(0).f_lineno, __debug__))
if __debug__:
  os.write(myfile, "LINE %s | LDAP FUNCTION __DEBUG__: %s \n" %(sys._getframe(0).f_lineno, __debug__))

而输出文件的内容是这样的:

LINE 82 | LDAP FUNCTION __DEBUG__: True 
LINE 83 | LDAP FUNCTION __DEBUG__: <type 'bool'> 
LINE 84 | LDAP FUNCTION __DEBUG__: True 
LINE 88 | LDAP FUNCTION __DEBUG__: True 
LINE 90 | LDAP FUNCTION __DEBUG__: True 

前面三条语句(第82-84行)是我想到的所有检查 __debug__ 是否“真实”的方法,所有这三种方式都表明 __debug__ 是 True。同样,把 __debug__ 转换成布尔值后再进行 if 判断(第88行)也按预期工作。第90行是一个简单的检查。

__debug__ 的工作方式上,我是不是遗漏了什么,导致了这个问题?

注意: 我在处理 python-ldap 模块中的 _ldap_function_call 函数时发现了这个问题。只有在使用 IIS 时我才会遇到这个错误 - 在 Django 的开发服务器上一切正常。

1 个回答

12

如果你重新绑定了 __debug__,可能会导致和这个问题一模一样的情况。

这是因为 __debug__ 有点神奇。在模块编译的时候,处理字面量的代码也会处理这些神奇的常量,比如 ...NoneTrueFalse__debug__。(你可以看看,比如在expr_constant这个地方。)

如果你用 dis 来查看你的代码的字节码,你会发现 if __debug__: 这样的语句要么完全被移除,要么用 LOAD_CONST 来加载编译时的 debug 常量,而 if bool(__debug__): 这样的语句则用 LOAD_GLOBAL 来加载 __debug__ 的值。

当然,这两个值是保证相同的……除非你重新绑定了 __debug__。在大约 2.3 版本的时候,直接写 __debug__ = False 就变成不合法了。在 2.7 和 3.0 版本中,绑定任何名为 __debug__ 的属性都是不合法的,这意味着你不能再像 sys.modules[__name__].__debug__ = False 这样做了。不过你仍然可以做,比如 globals()['__debug__'] = False

无论如何,你都会得到相同的效果:

if __debug__:
    print "debug"
if bool(__debug__):
    print "bool"

import sys
sys.modules[__name__].__debug__ = False

if __debug__:
    print "debug2"
if bool(__debug__):
    print "bool2"

这会打印出:

debug
bool
debug2

同样的情况也适用于当你用 python -O 运行代码时将其设置为 True。

撰写回答