Python调试技巧

164

https://gist.github.com/rduplain/4983839 - Sergey Orshanskiy
18个回答

139

PDB

您可以使用pdb模块,在任何地方插入pdb.set_trace(),它将起到断点的作用。

>>> import pdb
>>> a="a string"
>>> pdb.set_trace()
--Return--
> <stdin>(1)<module>()->None
(Pdb) p a
'a string'
(Pdb)

要继续执行,请使用c(或contcontinue)。

可以使用pdb执行任意Python表达式。例如,如果您发现错误,可以更正代码,然后键入一个类型表达式,以在运行代码中具有相同的效果

ipdb是IPython的pdb版本。它允许在所有IPython功能中使用pdb,包括制表符完成。

还可以设置pdb自动运行未捕获的异常。

Pydb被编写为pdb的增强版本。好处?


这是一篇关于使用pdb的文章:http://sontek.net/debugging-python-with-pdb - sontek
就我个人而言,我更喜欢ipdb - Sardathrion - against SE abuse
1
似乎有一个名为 pydbgr 的 pydb 重写版本。 - Ehtesh Choudhury
SublimeText有一个非常棒的插件,可以在代码中添加Python断点:https://sublime.wbond.net/packages/Python%20Breakpoints - Dennis Golomazov
如果您正在开发Web应用程序,请在调试模式下为myserver.com/pdb添加一个视图,该视图只需执行import pdb; pdb.set_trace()。如果您正在使用具有交互式调试器的Flask/Werkzeug,则还可以创建一个视图,只需执行assert False - Sergey Orshanskiy

78

http://pypi.python.org/pypi/pudb是一个全屏幕、基于控制台的Python调试器。

它的目标是在更轻量级和键盘友好的方式中提供现代GUI调试器的所有优点。 PuDB允许您在终端中调试代码,就在您编写和测试它的地方。如果您使用过出色但现在古老的基于DOS的Turbo Pascal或C工具,则PuDB的用户界面可能会很熟悉。

pudb screenshot

非常适用于调试独立的脚本,只需运行:

python -m pudb.run my-script.py

使用 pip install pudb 进行安装。 - congusbongus

40

如果你在使用pdb,你可以为快捷键定义别名。我用的是:

# Ned's .pdbrc

# Print a dictionary, sorted. %1 is the dict, %2 is the prefix for the names.
alias p_ for k in sorted(%1.keys()): print "%s%-15s= %-80.80s" % ("%2",k,repr(%1[k]))

# Print the instance variables of a thing.
alias pi p_ %1.__dict__ %1.

# Print the instance variables of self.
alias ps pi self

# Print the locals.
alias pl p_ locals() local:

# Next and list, and step and list.
alias nl n;;l
alias sl s;;l

# Short cuts for walking up and down the stack
alias uu u;;u
alias uuu u;;u;;u
alias uuuu u;;u;;u;;u
alias uuuuu u;;u;;u;;u;;u
alias dd d;;d
alias ddd d;;d;;d
alias dddd d;;d;;d;;d
alias ddddd d;;d;;d;;d;;d

你如何定义这些别名? - Casebash
9
请将这些内容放入~/.pdbrc文件中。 - Ned Batchelder
在Windows上,您可以将其放入 ~/_ipython/ipythonrc.ini 文件中。 - fastmultiplication

33

日志记录

Python已经有一个极好的内置日志记录模块。你可能想使用这里的日志记录模板

日志记录模块让你指定重要性级别; 在调试期间,你可以记录所有内容,而在正常运行期间,你可能只记录关键信息。你可以开启或关闭记录。

大多数人只是使用基本的打印语句进行调试,然后删除打印语句。最好的方法是将它们保留下来,但禁用它们; 然后,当你有另一个错误时,你可以重新启用所有内容并查看日志。

这可以是调试需要快速执行任务的程序的最佳方式,例如需要在网络连接的另一端超时并且失去连接之前响应的网络程序。你可能没有时间单步执行调试器;但是你可以让你的代码运行,并记录所有内容,然后仔细研究日志,找出真正发生了什么。

编辑:模板的原始URL为:http://aymanh.com/python-debugging-techniques

此页面已丢失,因此我用指向archive.org保存的快照的引用替换了它:http://web.archive.org/web/20120819135307/http://aymanh.com/python-debugging-techniques

如果它再次消失,这里是我提到的模板。这是从博客中提取的代码;我没有写过它。

import logging
import optparse

LOGGING_LEVELS = {'critical': logging.CRITICAL,
                  'error': logging.ERROR,
                  'warning': logging.WARNING,
                  'info': logging.INFO,
                  'debug': logging.DEBUG}

def main():
  parser = optparse.OptionParser()
  parser.add_option('-l', '--logging-level', help='Logging level')
  parser.add_option('-f', '--logging-file', help='Logging file name')
  (options, args) = parser.parse_args()
  logging_level = LOGGING_LEVELS.get(options.logging_level, logging.NOTSET)
  logging.basicConfig(level=logging_level, filename=options.logging_file,
                      format='%(asctime)s %(levelname)s: %(message)s',
                      datefmt='%Y-%m-%d %H:%M:%S')

  # Your program goes here.
  # You can access command-line arguments using the args variable.

if __name__ == '__main__':
  main()

以下是他关于如何使用上述内容的说明。再次强调,这并非由我创作:


默认情况下,logging模块会输出critical(严重)、error(错误)和warning(警告)级别的消息。要将所有级别的消息输出,可以使用以下代码:

$ ./your-program.py --logging=debug

要将日志消息发送到名为 debug.log 的文件,请使用:

$ ./your-program.py --logging-level=debug --logging-file=debug.log


1
日志模块的问题在于它在处理Unicode上存在严重的问题,需要多种变通方法才能使其在国际化应用程序中正常工作。然而,这仍然是Python中最好的日志记录解决方案。 - Jacek Konieczny
链接“logging template here”已失效,请更新。 - Yohann

20
可以打印出哪些Python代码行被执行(感谢Geo!)。这有许多应用,例如,您可以修改它以检查何时调用特定函数或添加类似于## 使其仅跟踪特定行的内容。
code.interact将您带入交互式控制台。
import code; code.interact(local=locals())

如果您想轻松访问控制台历史记录,请查看: "我能像在shell中那样拥有历史机制吗?"(需要向下查找)。
可以为解释器启用自动完成。

19

ipdb就像pdb一样,但比它更棒,它具有ipython的强大功能。


5
你能否增加一些关于它能做什么的细节? - Casebash

17

print语句

  • 一些人建议使用debug_print函数代替print,以便轻松禁用
  • pprint模块对于复杂的结构非常宝贵

3
当所有调试器都失败时,打印输出是您的好朋友。是的,debug_print将是一个不错的补充。 - Anurag Uniyal
通常我会先打印输出,然后再进行调试,除非我知道我能通过跟踪特定部分来解决问题。 - Casebash
4
实际上,日志模块就是这么做的。 - Bite code
是的,但需要设置日志记录。荣誉之后我会学习如何使用该模块。 - Casebash
print 可以在简单情况下非常有用,特别是在开发启动时间短的项目时。但另一方面,它可能会使人上瘾,并在更复杂的情况下使用它通常会导致头痛,而使用 pdb 或任何其他调试器则不会。 - vinilios
显示剩余2条评论

16

调试脚本的显而易见的方法

python -m pdb script.py
  • 当该脚本引发异常时很有用
  • 在使用虚拟环境且pdb命令未与虚拟环境的Python版本一起运行时非常有用。

如果您不确定该脚本的确切位置

python -m pdb ``which <python-script-name>``

15

15

PyDev

PyDev拥有一个非常好的交互式调试器。它拥有观察表达式、鼠标悬停可评估、线程和堆栈列表以及(几乎)所有你从现代视觉调试器中期望的通用设施。你甚至可以连接到正在运行的进程并进行远程调试。

然而,像其他视觉调试器一样,我发现它主要用于简单问题,或者在我尝试了所有其他方法后用于非常复杂的问题。我仍然大多数情况下使用日志来完成大部分的工作。


它是否具有编辑并继续的能力? - Casebash
@CaseBash 不,它目前还没有,但是这个功能已经计划了。即使没有这个功能,设置/取消断点和查看变量值的速度和便捷性仍然非常有用。 - Jiaaro

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