Python 调试技巧

调试 Python 的最佳技巧是什么?

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

相关资料

370574 次浏览

print报表

  • 有些人推荐使用 debug_print函数代替打印,以便于禁用
  • pprint模块对于复杂的结构来说是非常宝贵的

私隐专员公署

您可以使用 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 的一个增强版本?

Ipdb 与 pdb 类似,具有 ipython 的优秀特性。

可以打印什么 执行 Python 行(感谢 Geo!).这有很多应用程序,例如,您可以修改它来检查什么时候调用特定的函数,或者添加类似 # # 的东西,使它只跟踪特定的行。

Interactive 将您带入一个交互式控制台

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

如果您希望能够轻松地访问您的控制台历史记录,请查看: “ 我可以有一个历史机制,像在外壳?”(将不得不向下寻找它)。

可以为 翻译启用自动完成。

在可能的情况下,我在 emacs 中使用 M-x pdb进行源代码级调试。

伐木

Python 已经有了一个优秀的 内置日志记录模块

日志记录模块允许您指定重要性级别; 在调试期间,您可以记录所有内容,而在正常操作期间,您可能只记录关键内容。你可以随意开关。

大多数人只是使用基本的 print 语句进行调试,然后删除 print 语句。最好保留它们,但禁用它们; 然后,当您有另一个 bug 时,您可以重新启用所有内容并查看您的日志。

这可能是调试需要快速完成任务的程序的最佳方法,例如,需要在网络连接的另一端超时并消失之前做出响应的网络程序。您可能没有太多的时间来单步执行调试器; 但是您可以让代码运行,并记录所有内容,然后仔细研究日志并弄清楚到底发生了什么。

编辑: 模板的原始 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

PyDev

PyDev 有一个非常好的交互式调试器。它具有监视表达式、悬停计算、线程和堆栈列表,以及(几乎)所有现代可视化调试器的常用功能。您甚至可以附加到正在运行的进程并进行远程调试。

但是,与其他可视化调试器一样,我发现它主要用于简单的问题,或者在尝试了所有其他方法之后用于非常复杂的问题。现在大部分重活还是我来干。

在 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 一起使用,WinPDB 是一个可靠的图形化调试器。因为我知道您会问,它可以完成我期望图形调试器完成的所有工作:)

我使用 nose.tools中的 pdb,这样我就可以调试单元测试和普通代码。

最后,F7映射将打印一个回溯(类似于异常冒泡到堆栈顶部时得到的回溯)。我发现它真的很有用,不止几次。

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

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

如果你使用 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

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

有几个技巧 给你。这些包括

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

为类定义有用的 公司代表()方法(这样您就可以看到对象是什么) ,并使用 repr ()或“% r”% (...)或“ ... {0!你好。.".调试消息/日志中的 format (...)是高效调试的关键。

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

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

它的目标是以更轻量级和键盘友好的包提供现代基于 GUI 的调试器的所有细节。PuDB 允许您在编写和测试代码的地方调试代码——在终端中。如果您使用过优秀的(但是现在比较古老的)基于 DOS 的 Turbo Pascal 或 C 工具,PuDB 的 UI 可能看起来很眼熟。

pudb screenshot

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

python -m pudb.run my-script.py

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

python -m pdb script.py
  • 当该脚本引发异常时非常有用
  • 当使用 viralenv 和 pdb 命令不能在 venvs python 版本中运行时,这个命令非常有用。

如果你不知道剧本的确切位置

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

如果您熟悉 VisualStudio,那么您需要的是 用于 VisualStudio 的 Python 工具

enter image description here

如果您不喜欢在调试器中花费时间(也不喜欢 pdb命令行接口的可用性差) ,那么可以转储执行 Trace并在以后对其进行分析。例如:

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

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

为了使定制跟踪输出和编写自己的跟踪程序更加容易,我将一些代码放在 Xtrace模块(公共域)中。

安德烈亚斯 · 泽勒(Andreas Zeller)在 Udacity 上开设了一门名为“ 软件调试”的完整在线课程,内容包括调试技巧:

课程摘要

在本课程中,你将学习如何系统地调试程序,如何 来自动化调试过程和构建几个自动化的 Python 中的调试工具。

为什么要上这门课?

在本课程结束时,你将对 系统调试,将知道如何自动调试和将 已经用 Python 构建了几个函数式调试工具。

先决条件和要求

Udacity 水平的编程和 Python 基础知识 要求 CS101或更高。基本的面向对象理解 编程是有帮助的。

强烈推荐。

如果您希望以一种可读的方式打印调用堆栈,请查看以下实用程序: 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))

和姜戈一起跑:

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