Python部落(python.freelycode.com)组织翻译,禁止转载,欢迎转发。
与使用p和pp打印表达式类似,你可以使用命令display [expression]告诉pdb自动显示表达式的值,如果它改变,执行停止。使用命令undisplay [expression]来清除显示表达式。
以下是这两个命令的语法和描述:
下面是example4display.py的一个例子,演示了它在循环中的使用:
在上面的输出中,pdb自动显示char变量的值,因为每次命中断点时,其值都发生了变化。有时这是有用的,正是你想要的,但还有另一种使用display的方式。
你可以多次输入display来构建表达式的观察列表。这比用p更容易。添加完所有感兴趣的表达式后,只需输入display查看当前值即可:
最后这一节我们将建立在目前所了解的内容上。我参考电话系统的来电者识别功能使用“调用者ID”这一称呼。这正是这个例子演示的内容,除了它适用于Python。
以下是主脚本example5.py的源代码:
以下是实用程序模块fileutil.py:
在这种情况下,想象在实用程序模块get_path()中有一个带有函数的大型代码库,该函数被无效输入调用。但是它是从不同包中的不同地方被调用的。
你如何找到调用者是谁?
使用命令w(where)打印堆栈跟踪,最近一帧在底部:
如果这看起来让你困惑或者你不确定堆栈跟踪或帧是什么,请不要担心。我将在下面解释这些术语。它们并不像听起来那么难。
由于最近帧在底部,所以从那里开始并从底部向上阅读。查看以 - >开头的行,但跳过第一个实例,因为这是在函数get_path()中使用pdb.set_trace()进入pdb的地方。在这个例子中,调用函数get_path()的代码行是:
每个 - >上方的行包含文件名,行号(括号中)以及源代码行所在的函数名称。因此调用者是:
在这个小示例中,为了演示的目的,这并不奇怪,但想象一个大型应用程序,你可以在其中设置一个带条件的断点以标识输入值发生错误的位置。
现在我们知道了如何找到调用者。
那么堆栈跟踪和帧呢?
堆栈跟踪只是Python为创建跟踪函数调用而创建的所有帧的列表。帧是Python在调用函数时创建的数据结构,在返回时即删除。堆栈只是在任何时间点有序的帧或函数调用列表。(函数调用)堆栈在应用程序的整个生命周期中随着函数的调用而增长和缩小,然后返回。
打印时,这个有序的帧列表,也即堆栈,被称为堆栈跟踪。你随时可以通过输入命令w来查看它,就像我们在上面找到调用者一样。
| 有关详细信息,请参阅Wikipedia上调用堆栈的文章。
为了更好地理解pdb,让我们仔细看看w的帮助:
“当前帧”是什么意思?
将当前帧视为pdb已停止执行的当前函数。换句话说,当前帧是你的程序当前暂停的位置,并用作p(print)命令的参照系。
当需要时,p和其他命令将使用当前帧作为上下文。在命令p的情况下,当前帧将用于查找和打印变量引用。
当pdb打印堆栈跟踪时,箭头>表示当前帧。
这有用吗?
你可以使用两个命令u(up)和d(down)来更改当前帧。与p结合使用,你可以在任何帧的调用堆栈中的任意点检查程序中的变量和状态。
以下是这两个命令的语法和描述:
我们来看一个使用u和d命令的例子。在这种情况下,我们要检查example5.py中函数get_file_info()的局部变量full_fname。为了做到这一点,我们必须使用命令u将当前帧提升一个级别:
调用pdb.set_trace()是在fileutil.py中的get_path()函数中,所以当前帧最初设置在那。你可以在上面的第一行输出中看到它:
要访问和打印example5.py中的函数get_file_info()里的局部变量full_fname,使用命令u向上移动一个级别:
注意在上面的u的输出中,pdb在第一行的开始处输出了箭头>。这是pdb让你知道帧被改变了,这个源位置现在是当前帧。现在可以访问变量full_fname。另外,重要的是要实现以第二行上的 - >开始的代码行。由于帧被移到堆栈上,所以调用了fileutil.get_path()。使用u,我们将堆栈(从某种意义上来说)移动到调用fileutil.get_path()的函数example5.get_file_info()中。
继续这个例子,在打印完full_fname之后,当前帧使用d移动到其原始位置,并且打印了get_path()中的局部变量fname。
如果我们想,我们可以通过将计数参数传递给u或d来一次移动多个帧。例如,我们可以通过输入u 2来移动到example5.py中的模块级别:
在调试和思考许多不同的事情时,很容易忘记程序执行到哪一步。请记住,你始终可以使用恰当的命令w(where)来查看执行暂停的位置以及当前帧的位置。
一旦你使用pdb一段时间,你会发现要了解全部知识还有很长的路要走。你始终可以通过h命令获得帮助。
只需输入h或help<topic>获取所有命令的列表或帮助你完成特定的命令或。
为了快速参考,这里列出了一些重要的命令:
在本教程中,我们介绍了pdb的一些基本和常见用法:
打印表达式
使用n(next)和s(step)单步执行代码
使用断点
使用unt(until)继续执行
显示表达式
找到函数的调用者
希望这对你有所帮助。如果你想了解更多信息,请参阅:
在pdb提示符下输入(Pdb)h pdb获取pdb的完整文档
Python的pdb文档
示例中使用的源代码可以在关联的GitHub存储库中找到。 请务必查看我们可打印的pdb命令参考,你可以在调试时将其用作备忘手册。
此外,如果你想学习使用基于GUI的Python调试器,请阅读我们的Python IDE和编辑指南,了解哪些选择最适合你。祝Python编程愉快!
英文原文:https://realpython.com/python-debugging-pdb/
译者:β