仅使用打印语句进行调试


109

最近我一直在用Python编写很多代码。而且我一直在处理以前从未使用过的数据,使用从未见过的公式来处理大型文件。所有这些使我写了很多打印语句来验证是否一切正常,并确定故障点。但是,通常,输出太多信息不是一个好习惯。仅当我要调试时才使用打印语句,而当我不希望打印它们时如何跳过它们?

Answers:


161

logging模块具有您想要的一切。乍一看似乎有些多余,但只使用您需要的零件。我推荐使用logging.basicConfig切换日志级别stderr简单的日志方法debuginfowarningerrorcritical

import logging, sys
logging.basicConfig(stream=sys.stderr, level=logging.DEBUG)
logging.debug('A debug message!')
logging.info('We processed %d records', len(processed_records))

5
另外,以防您像我一样安装此模块时遇到麻烦;日志记录是标准库的一部分-无需使用PIP虚拟环境中安装时甚至
阿姆鲁

如何设置日志记录的级别,使其仅显示错误而不调试消息?
爱德华多·皮尼亚特利

@EduardoPignatelli levelbasicConfig通话中设置为logging.ERROR
马特·乔纳

恐怕这在jupyter实验室1.2.6上不起作用。您只能设置一次日志记录级别,并且正在使用的重置logging.basicConfig(stream=sys.stderr, level=logging.ERROR)将不起作用。重新启动内核并设置新级别是可行的,但这对我来说是一种解决方法。
Eduardo Pignatelli

@EduardoPignatelli,您应该为此提出另一个问题。但是可能您需要直接更改root记录程序上的级别,jupyter可能在您之前调用了basicConfig。
马特·乔纳

28

一种简单的方法是调用日志记录函数:

DEBUG = True

def log(s):
    if DEBUG:
        print s

log("hello world")

然后,可以更改DEBUG有无日志记录的值并运行代码。

标准logging模块对此具有更完善的机制。


5
从长远来看,使用提供的日志记录模块可能比自己动手滚动日志模块更好(即使看起来更复杂)。
mgiuca 2011年

11
没错,但它是值得理解一个人如何推出自己的。
Greg Hewgill

1
确实。上面是一个很好的logging工作原理(非常简单的层次)。
mgiuca

这是我用于aws lambda的那个。
crsuarezf

21

使用日志记录内置库模块代替打印。

创建一个Logger对象(例如logger),然后在此之后,每当插入调试打印时,您只需放置:

logger.debug("Some string")

您可以logger.setLevel在程序开始时使用来设置输出电平。如果将其设置为DEBUG,它将打印所有调试信息。将其设置为INFO或更高,所有调试将立即消失。

您还可以使用它记录不同级别(信息,警告和错误)的更严重的事件。


12

首先,我将第二次提名python的日志记录框架。但是,请谨慎使用它。具体来说:让日志记录框架扩展您的变量,而不要自己做。例如,代替:

logging.debug("datastructure: %r" % complex_dict_structure)

确保您这样做:

logging.debug("datastructure: %r", complex_dict_structure)

因为尽管它们看上去很相似,但第一个版本即使已禁用也会产生repr()成本。第二个版本避免这种情况。同样,如果您自己动手,我建议采取以下措施:

def debug_stdout(sfunc):
    print(sfunc())

debug = debug_stdout

通过以下方式调用:

debug(lambda: "datastructure: %r" % complex_dict_structure)

如果您通过执行以下操作将其禁用,这将再次避免开销:

def debug_noop(*args, **kwargs):
    pass

debug = debug_noop

除非它们是1)计算成本高或2)debug语句处于n ^ 3循环之类的中间,否则计算这些字符串的开销可能并不重要。并不是说我对此一无所知。


在日志记录howto中的“优化”下有关于此重要主题的更多信息:docs.python.org/3/howto/logging.html#optimization
Martin CR

7

我对其他人一无所知,但是我习惯于定义一个“全局常量”DEBUG),然后定义一个仅在时才debug(msg)打印的全局函数()。msgDEBUG == True

然后,我编写如下的调试语句:

debug('My value: %d' % value)

...然后我进行单元测试,再也没有做过!:)


单元测试哈。好的,那就是另一件事,然后
去接

1
我不想阻止单元测试-这是必不可少的。但是我不认为它可以代替日志记录,甚至可以作为一种调试技术。我仍然做了很多印刷工作以快速进行测试。
mgiuca'7

@crazyaboutliv-正确完成单元测试非常棒。看看本章深入了解python的这一章,以获取一个简洁,简洁,易于遵循的演示文稿
mac

@mgiuca-我也进行快速打印,但是print()将我的代码提高到通过测试所需的级别只是几两遍。我print()到处都没结束过。日志记录也很酷!:)
mac

2
@mac看来您的链接现在需要一个显式的'www'-现在在此处托管
culix 2012年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.