#ifdef DEBUG 的 Python 等效方式是什么?

59

在 C 语言中,我们编写的代码类似于:

#ifdef DEBUG
printf("Some debug log... This could probably be achieved by python logging.Logger");
/* Do some sanity check code */
assert someCondition
/* More complex sanitycheck */
while(list->next){
assert fooCheck(list)
}

#endif

有方法可以用Python做到这个吗?

编辑:我得到了我的答案,还有更多 :) Paolo、Steven Rumbalski和J Sebastian给了我我正在寻找的信息。感谢das详细的答案,虽然我现在可能不会使用预处理器。

J Sebastian的评论被删除了,因为他在发布评论的答案被删除了,我想。 他说我可以使用Logger中的isEnabledFor()方法来提供一个条件。

感谢大家的回答。这是我的第一个问题。我希望我能接受Paolo或J Sebastian的答案。但由于那些作为评论提供,所以我将接受DAS的答案。

我可能会使用http://nestedinfiniteloops.wordpress.com/2012/01/15/if-debug-python-flavoured/或Logger.isEnabledFor()


2
https://dev59.com/znI-5IYBdhLWcg3w9thw 和 http://nestedinfiniteloops.wordpress.com/2012/01/15/if-debug-python-flavoured/ - Paolo Moretti
4
全局设置 DEBUG 并使用简单的 if 语句 if DEBUG:... 有什么问题吗? - Steven Rumbalski
6个回答

116

在您的代码中使用__debug__

if __debug__:
    print 'Debug ON'
else:
    print 'Debug OFF'
创建一个名为abc.py的脚本,并使用上面的代码,然后:
  1. 使用命令python -O abc.py运行。
  2. 使用命令python abc.py运行。
观察它们之间的区别。

3
实际上,如果表达式是一个静态值(例如 TrueFalseNone__debug__00.0),Python 将完全删除 if 语句,这使得 if __debug__ 成为编译时指令而不是运行时检查。 - doctaphred
在 Windows 7 和 10 上,使用 Python 3.7.4,在 cmd.exe 或 Console 2 中通过文件名执行 Python 程序时,__debug__ 始终为 True,这对我不起作用。 - PointedEars
6
为什么__debug__默认为真?将__debug__默认设置为假,然后由Python -O设置为真不是更好吗? - Edu
4
因为“O”代表着优化(Optimise),所以使用-O标志会将__debug__设置为false,这样可以优化掉那些部分,并删除assert语句。-OO还会删除文档字符串(docstrings)。 - Sam Rockett
默认情况下,将__debug__设置为False会更加直观。 - ijoseph
显示剩余3条评论

37

Mohammad's answer 是正确的方法:使用 if __debug__

实际上,如果表达式是静态常量(如TrueFalseNone__debug__00.0),Python会完全删除if语句,使if __debug__成为编译时指令而不是运行时检查:

>>> def test():
...     if __debug__:
...         return 'debug'
...     return 'not debug'
...
>>> import dis
>>> dis.dis(test)
  3           0 LOAD_CONST               1 ('debug')
              2 RETURN_VALUE

-O选项的详细说明在Python文档中有关于命令行选项,并且有类似的优化方法适用于assert语句

因此,不要使用外部预处理器 - 对于此目的,您已经内置了一个!


给回复点了个赞 :) - Mohammad Shahid Siddiqui
这似乎在稍微复杂一些的情况下会失败,例如: if not __debug__: return 'not debug' else: return 'debug' import dis dis.dis(test)``` 结果为: 2 0 LOAD_CONST 1 (True) 2 POP_JUMP_IF_TRUE 8 3 4 LOAD_CONST 2 ('not debug') 6 RETURN_VALUE 5 >> 8 LOAD_CONST 3 ('debug') 10 RETURN_VALUE 12 LOAD_CONST 0 (None) 14 RETURN_VALUE - Gajo Petrovic
这在 Python 2 中是正确的(Python 2 已于 1 月 1 日停止生命周期 -- 是时候升级了!),但在 Python 3 中,许多静态可计算表达式(包括 not __debug__)在编译时被求值,并且无法访问的分支中的字节码会被删除。 - doctaphred
@PointedEars 你是否像Mohammad的回答和链接文档中所解释的那样传递了-O选项?在类Unix系统上,如果要直接执行Python脚本并提供解释器选项,可以将它们添加到脚本开头的shebang行中:#!/usr/bin/env python -O。不确定Windows的等效方式是什么。但是除非以某种方式给解释器传递该标志,否则__debug__确实始终为真。 - doctaphred
@doctaphred,我不知道“-O标志”的意思,所以在我的脚本中没有传递它。现在明白了,谢谢。我稍后会尝试一下。 - PointedEars
显示剩余2条评论

11
您需要的是Python的预处理器。一般有以下三种选择:
  1. 编写一个自制脚本/程序,它会基于某些模板替换源代码的部分,然后将结果传递给解释器(可能比较困难)
  2. 使用特殊用途的Python预处理器,例如pppp - Poor's Python Pre-Processor
  3. 使用通用预处理器,例如GPP
我建议首先尝试使用pppp ;) 与设置DEBUG标志并运行代码if (DEBUG == True)相比,预处理器的主要优点在于条件检查也会消耗CPU周期,因此最好删除不需要运行的代码(如果Python解释器没有这样做),而不是跳过它。

2
cog.py是另一个不错的预处理器(其中预处理语言本身是Python):http://nedbatchelder.com/code/cog/ - Mr Fooz
看起来上面的链接到 pppp - Poor's Python Pre-Processor 已经失效了。这里是一个指向 github 上代码的链接。 - user2070305
2
对于简单的 #ifdef DEBUG 情况,if __debug__ 完全足够,并且不会产生任何运行时成本。请参见 https://dev59.com/nWYr5IYBdhLWcg3w29lI#45821863。 - doctaphred

2

检查sys.gettrace()的结果是否为None。这意味着没有调试器。

import sys
if sys.gettrace():
    print("debug mode!")
else:
   print("debug mode is off!")

这是唯一一个对我有效的。 - thethiny

2

0

我采用另一种方法 - 作为独立/直接运行测试模块:

import ...

DEBUG = False

....

def main():
    pass

if __name__ == '__main__':
    DEBUG = True
    main()

它可以灵活地作为项目模块运行,当独立运行时DEBUG将为True,否则为False。例如,从本地文件或请求中加载数据很适合使用此功能:

def load_csv():
    fn = get_csv_filename()  # will return path depending DEBUG
    if DEBUG:
        if not exists(fn):
            store_df(request_bond_list(), fn)
        return pd.read_csv(fn)
    return request_bond_list()

这也帮助我在DEBUG模式下控制路径。如您所知,当模块放置在与主代码不同的目录中时,在我们将模块作为独立运行(进行测试)时,路径将是'module'目录,但当我们在'main'内实现此模块的方法时,路径将设置为项目的根目录。因此,您可以使用DEBUG来调整不同情况下的路径。

(或者您可以直接更改“if __name__ =='__ main__':”中的'path')


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接