Python调试技巧


164

您调试Python的最佳秘诀是什么?

请不要只列出特定的调试器而不必说出它实际上可以做什么。

有关


Answers:


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版本。它允许将pdb与所有IPython功能一起使用,包括制表符补全。

也可以将pdb设置为在未捕获的异常上自动运行

Pydb被编写为Pdb的增强版本。有好处吗?


这是有关使用pdb的文章:sontek.net/debugging-python-with-pdb
sontek 2010年

就个人而言,我更喜欢ipdb
Sardathrion-反对SE滥用2012年

1
显然存在pydb的重写,称为pydbgr
Ehtesh Choudhury,

SublimeText有一个很棒的插件,可以在代码中添加python断点:sublime.wbond.net/packages/Python%20Breakpoints
Dennis Golomazov 2014年

如果您要开发Web应用程序,则myserver.com/pdb只需在调试模式下添加一个视图即可import pdb; pdb.set_trace()。如果您使用的是具有交互式调试器的Flask / Werkzeug,那么您也可以拥有的视图assert False
osa 2014年

78

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

它的目标是以更加轻巧和键盘友好的软件包提供基于GUI的现代调试器的所有优点。PuDB允许您在终端中在编写和测试代码的地方调试代码。如果您使用过出色的(但时至今日仍是古老的)基于DOS的Turbo Pascal或C工具,那么PuDB的UI可能看起来很熟悉。

pudb屏幕截图

非常适合调试独立脚本,只需运行

python -m pudb.run my-script.py

安装于pip install pudb
congusbongus 2014年

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()

这是他对上述用法的解释。同样,我对此没有功劳:


默认情况下,日志记录模块会打印严重,错误和警告消息。要更改此设置以打印所有级别,请使用:

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

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

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


1
日志记录模块的问题在于它严重破坏了Unicode,并且需要各种变通办法才能使其在国际化的应用程序中运行。虽然,这仍然是Python最好的日志记录解决方案。
Jacek Konieczny 2010年

链接“此处记录模板”已失效。请更新。
Yohann

20

可以打印执行了哪些Python行(感谢Geo!)。它具有许多应用程序,例如,您可以对其进行修改以检查何时调用了特定功能,或者添加诸如##之类的内容使其仅跟踪特定行。

code.interact带您进入交互式控制台

import code; code.interact(local=locals())

如果您希望能够轻松访问控制台历史记录,请查看:“ 我可以在shell中使用历史记录机制吗? ”(将不得不查找它)。

可以为解释器启用自动完成功能。



17

print 陈述

  • 有人建议使用debug_print功能而不是打印功能来轻松禁用
  • pprint模块对于复杂的结构是无价的

3
当每个调试器失败时+ 1,print是您的朋友,是的,debug_print将是一个不错的选择
Anurag Uniyal 09年

我通常先打印,然后再调试,除非我知道可以通过跟踪特定部分来解决
Casebash

4
实际上,日志模块就是这样做的。
e-satis

是的,但是必须设置日志记录。我将在
获奖

在简单情况下,尤其是在开发启动时间短的项目时,打印可能很有用。另一方面,它可能会让人上瘾,并且在更复杂的情况下通过pdb或任何其他调试器使用它通常会使您头疼
vinilios 2011年

16

调试脚本的明显方法

python -m pdb script.py
  • 该脚本引发异常时很有用
  • 当使用virtualenv和pdb命令未与venvs python版本一起运行时很有用。

如果您不确切知道该脚本在哪里

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

15

佩德夫

PyDev有一个很好的交互式调试器。它具有监视表达式,求值悬停,线程和堆栈列表,以及(几乎)您希望从现代视觉调试器获得的所有常用功能。您甚至可以附加到正在运行的进程并进行远程调试。

但是,像其他可视调试器一样,我发现它主要用于简单的问题,或者在尝试了所有其他方法之后对非常复杂的问题很有用。我仍然会进行大部分繁重的伐木工作。


它具有编辑并继续的功能吗?
Casebash

@CaseBash否,不是的,但是该功能已计划中。即使没有它,设置/取消断点和查看变量值的速度和便捷性仍然非常有用
Jiaaro


12

Winpdb非常好,与它的名称相反,它是完全跨平台的。

它有一个非常好的提示,基于 GUI调试器,并支持远程调试。


@Casebash-添加了更多详细信息
Orip

1
+1这是到目前为止我发现的唯一可以处理多线程的python调试器。
Lee Netherton

要小心多线程的“处理”-任何线程中的任何异常都会导致整个进程冻结。如果您意识到这不是一件坏事,否则就很痛苦
Walt W

该项目看起来已死于2014
Alojz Janez

7

在Vim中,我具有以下三个绑定:

map <F9> Oimport rpdb2; rpdb2.start_embedded_debugger("asdf") #BREAK<esc>
map <F8> Ofrom nose.tools import set_trace; set_trace() #BREAK<esc>
map <F7> Oimport traceback, sys; traceback.print_exception(*sys.exc_info()) #TRACEBACK<esc>

rpdb2是一个远程Python调试器,可与可靠的图形调试器WinPDB一起使用。因为我知道您会问,所以它可以完成我期望图形调试器完成的所有工作:)

我使用pdbfrom nose.tools来调试单元测试和普通代码。

最后,F7映射将打印回溯(类似于异常冒泡到堆栈顶部时所得到的那种)。我发现它确实有用了很多次。


4

为类定义有用的repr()方法(以便您可以看到对象是什么),并使用repr()或“%r”%(...)或“ ... {0!r} ..” .. format (...)在您的调试消息/日志中,恕我直言,这是高效调试的关键。

另外,其他答案中提到的调试器将使用repr()方法。


2

从正在运行的Python应用程序获取堆栈跟踪

有几个窍门在这里。这些包括

  • 通过发送信号进入解释器/打印堆栈跟踪
  • 从未经准备的Python流程中获取堆栈跟踪
  • 运行带有标志的解释器以使其对调试有用

2

如果您不喜欢花时间在调试器上(并且不喜欢pdb命令行界面的可用性很差),则可以转储执行跟踪并在以后进行分析。例如:

python -m trace -t setup.py install > execution.log

这会将所有setup.py install执行源代码转储到execution.log

为了使自定义跟踪输出和编写自己的跟踪器更加容易,我将一些代码放到了xtrace模块(公共域)中。


1

如果可能,我会M-x pdb在emacs中进行调试以进行源代码级调试。


1

Andreas Zeller在Udacity上提供了名为“ 软件调试 ” 的完整在线课程,其中包含有关调试的提示:

课程总结

在本课程中,您将学习如何系统地调试程序,如何自动化调试过程以及如何在Python中构建一些自动化调试工具。

为什么要上这门课?

在本课程的最后,您将对系统调试有深入的了解,将了解如何实现自动化调试,并且将使用Python构建一些功能调试工具。

先决条件和要求

需要具有Udacity CS101或更高级别的编程和Python的基础知识。对面向对象编程的基本理解会有所帮助。

强烈推荐。


0

如果您想要一种很好的图形方式以一种可读的方式打印您的调用堆栈,请查看此实用程序:https : //github.com/joerick/pyinstrument

从命令行运行:

python -m pyinstrument myscript.py [args...]

作为模块运行:

from pyinstrument import Profiler

profiler = Profiler()
profiler.start()

# code you want to profile

profiler.stop()
print(profiler.output_text(unicode=True, color=True))

用django运行:

只需添加pyinstrument.middleware.ProfilerMiddlewareMIDDLEWARE_CLASSES,然后添加?profile到请求URL的末尾以激活分析器。

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.